Advertisement
Guest User

poeiteminfo script - nomacro

a guest
Nov 6th, 2014
240
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 188.53 KB | None | 0 0
  1. ; Path of Exile Item Info Tooltip
  2. ;
  3. ; Version: 1.7.5 (hazydoc / IGN:Sadou)
  4. ;
  5. ; This script was originally based on the POE_iLVL_DPS-Revealer script (v1.2d) found here:
  6. ; https://www.pathofexile.com/forum/view-thread/594346
  7. ;
  8. ; Changes to the POE_iLVL_DPS-Revealer script as recent as it's version 1.4.1 have been
  9. ; brought over. Thank you Nipper4369 and Kislorod!
  10. ;
  11. ; The script has been added to substantially to enable the following features in addition to
  12. ; itemlevel and weapon DPS reveal:
  13. ;
  14. ; - show total affix statistic for rare items
  15. ; - show possible min-max ranges for all affixes on rare items
  16. ; - reveal the combination of difficult compound affixes (you might be surprised what you find)
  17. ; - show affix ranges for uniques
  18. ; - show map info (thank you, Kislorod and Necrolis)
  19. ; - show max socket info (thank you, Necrolis)
  20. ; - has the ability to convert currency items to chaos orbs (you can adjust the rates by editing
  21. ; <datadir>\CurrencyRates.txt)
  22. ; - can show which gems are valuable and/or drop-only (all user adjustable)
  23. ; - can show a reminder for uniques that are generally considered valuable (user adjustable as well)
  24. ; - adds a system tray icon and proper system tray description tooltip
  25. ;
  26. ; All of these features are user-adjustable by using a "database" of text files which come
  27. ; with the script and are easy to edit by non developers. See header comments in those files
  28. ; for format infos and data sources.
  29. ;
  30. ; Known issues:
  31. ;
  32. ; Even though there have been tons of tests made on composite affix combinations, I expect
  33. ; there to be edge cases still that may return an invalid or not found affix bracket.
  34. ; You can see these entries in the affix detail lines if they have the text "n/a" (not available)
  35. ; somewhere in them or if you see an empty range " - *". The star by the way marks ranges
  36. ; that have been added together for a guessed attempt as to the composition of a possible
  37. ; compound affix. If you see this star, take a closer look for a moment to check if the
  38. ; projection is correct. I expect these edge cases to be properly dealt with over time as the
  39. ; script matures. For now I'd estimate that at least 80% of the truly hard cases are correctly
  40. ; identified.
  41. ;
  42. ; Some background info: because the game concatenates values from multiple affix sources into
  43. ; one final entry on the ingame tooltip there is no reliable way to work backwards from the
  44. ; composite value to each individual part. For example, Stun Recovery can be added as suffix if
  45. ; it contributes alone, but can also be a prefix if it is a composite of Stun Recovery and
  46. ; Evasion Rating (or others). Because there is one final entry, while prefix and suffix can
  47. ; appear at the same time and will be added together, you can't reliably reverse engineer which
  48. ; affix contributed what part of the composite value. This is akin to taking a random source of
  49. ; numbers, adding them up to one value and then asking someone to work out backwards what the
  50. ; original source values were.
  51. ; Similarily, in cases like boosted Stun Recovery (1) and Evasion Rating (2) on an item in difficult
  52. ; cases there is no 100% reliable way to tell if the prefix "+ Evasion Rating / Block and Stun Recovery"
  53. ; contributed to both stats at once or if the suffix "+ Block and Stun Recovery" contributed to (1)
  54. ; and the prefix "+ Evasion Rating" cotributed to (2) or possibly a combination of both.
  55. ; Often it is possible to make guesses by working your way backwards from both partial affixes, by
  56. ; looking at the affix bracket ranges and the item level to see what is even possible to be there and
  57. ; what isn't. In the worst case for a double compound affix, all four ranges will be possible to be
  58. ; combined.
  59. ;
  60. ; I have tested the tooltip on many, many items in game from my own stash and from trade chat
  61. ; and I can say that in the overwhelming majority of cases the tooltip does indeed work correctly.
  62. ;
  63. ; IMPORTANT: as you may know, the total amount of affixes (w/o implicit mods) can be 6, of which
  64. ; 3 at most are prefixes and likewise 3 at most are suffixes. Be especially weary, then of cases
  65. ; where this prefix/suffix limit is overcapped. It may happen that the tooltip shows 4 suffixes,
  66. ; and 3 prefixes total. In this case the most likely explanation is that the script failed to properly
  67. ; determine composite affixes. Composite affixes ("Comp. Prefix" or "Comp. Suffix" in the tooltip)
  68. ; are two affix lines on the ingame tooltip that together form one single composite affix.
  69. ; Edit v1.4: This hasn't happened for a longer time now, but I am leaving this important note in
  70. ; so end users stay vigilant (assuming anyone even reads this wall of text :)).
  71. ;
  72. ; - I do not know which affixes are affected by +% Item Quality. Currently I have functions in place
  73. ; that can boost a range or a single value to adjust for Item Quality but currently these aren't used
  74. ; much. Partially this is also because it is not easy to tell if out-of-bounds cases are the result
  75. ; of faulty input data (I initially pulled data from the PoE mods compendium but later made the PoE
  76. ; homepage the authoritative source overruling data from other sources) or of other unreckognized and
  77. ; unhandled entities or systems.
  78. ;
  79. ; Todo:
  80. ;
  81. ; - handle ranges for implicit mods
  82. ;
  83. ; Notes:
  84. ;
  85. ; - Global values marked with an inline comment "d" are globals for debugging so they can be easily
  86. ; (re-)enabled using global search and replace. Marking variables as global means they will show
  87. ; up in AHK's Variables and contents view of the script.
  88. ;
  89. ; Needs AutoHotKey v1.0.45 or later
  90. ;
  91. ; Original credits:
  92. ;
  93. ; mcpower - for the base iLVL display of the script 5months ago before Immo.
  94. ; Immo - for the base iLVL display of the script.(Which was taken from mcpower.)
  95. ; olop4444 - for helping me figure out the calculations for Q20 items.
  96. ; Aeons - for a rewrite and fancy tooltips.
  97. ; kongyuyu - for base item level display.
  98. ; Fayted - for testing the script.
  99. ;
  100. ; Original author's comment:
  101. ;
  102. ; If you have any questions or comments please post them there as well. If you think you can help
  103. ; improve this project. I am looking for contributors. So Pm me if you think you can help.
  104. ;
  105. ; If you have a issue please post what version you are using.
  106. ; Reason being is that something that might be a issue might already be fixed.
  107. ;
  108.  
  109. ; Run test suites (see end of script)
  110. ; Note: don't set this to true for normal every day use...
  111. ; This is just for fellow developers.
  112. RunTests := False
  113.  
  114. #SingleInstance force
  115. #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
  116. #Persistent ; Stay open in background
  117. SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
  118. StringCaseSense, On ; Match strings with case.
  119.  
  120. ; OPTIONS
  121.  
  122. OnlyActiveIfPOEIsFront = 0 ; Set to 1 to make it so the script does nothing if Path of Exile window isn't the frontmost.
  123. ; If 0, the script also works if PoE isn't frontmost. This is handy for have the script parse
  124. ; textual item representations appearing somewhere else, like in the forums or text files.
  125.  
  126. ShowItemLevel = 1 ; Show item level and the item type's base level (enabled by default change to 0 to disable)
  127. ShowMaxSockets = 1 ; Show the max sockets based on ilvl and type
  128. ShowDamageCalculations = 1 ; Show damage projections (for weapons only)
  129.  
  130. ShowAffixTotals = 1 ; Show total affix statistics
  131. ShowAffixDetails = 1 ; Show detailed info about affixes
  132. ShowAffixLevel = 0 ; Show item level of the affix
  133. ShowAffixBracket = 1 ; Show range for the affix' bracket as is on the item
  134. ShowAffixMaxPossible = 1 ; Show max possible bracket for an affix based on the item's item level
  135. ShowAffixBracketTier = 1 ; Show a T# indicator of the tier the affix bracket is in.
  136. ; T1 being the highest possible, T2 second-to-highest and so on
  137.  
  138. TierRelativeToItemLevel = 0 ; When determining the affix bracket tier, take item level into consideration.
  139. ; However, this also means that the lower the item level the less the diversity
  140. ; of possible affix tiers since there aren't as many possibilities. This will
  141. ; give the illusion that a low level item might be really, really good when it
  142. ; has all T1 but in reality it can only have T1 since it's item level is so low
  143. ; it can only ever take the first bracket.
  144. ;
  145. ; If this option is set to 0, the tiers will always display relative to the full
  146. ; range of tiers available, ignoring the item level.
  147.  
  148. ShowCurrencyValueInChaos = 1 ; Convert the value of currency items into chaos orbs.
  149. ; This is based on the rates defined in <datadir>\CurrencyRates.txt
  150. ; You should edit this file with the current currency rates.
  151.  
  152. ShowUniqueEvaluation = 1 ; Display reminder when a unique is valuable.
  153. ; This is based on <datadir>\ValuableUniques.txt
  154. ; You can edit this file to suit your own needs.
  155.  
  156. ShowGemEvaluation = 1 ; Display reminder when a gem is valuable and/or drop only.
  157. ; This is based on <datadir>\ValuableGems.txt and <datadir>\DropOnlyGems.txt
  158. ; You can edit these files to suit your own needs.
  159.  
  160. GemQualityValueThreshold = 10 ; If the gem's added quality exceeds this value, consider it valuable regardless of which gem it is.
  161.  
  162. MaxSpanStartingFromFirst = 1 ; When showing max possible, don't just show the highest possible affix bracket
  163. ; but construct a pseudo range which spans the lower bound of the lowest possible
  164. ; bracket to the upper bound of the highest possible one.
  165. ;
  166. ; This is usually what you want to see when evaluating an item's worth. The exception
  167. ; being when you want to reroll an affix to the highest possible value within it's
  168. ; current bracket - then you need to see the affix range that is actually on the item
  169. ; right now.
  170.  
  171. CompactDoubleRanges = 1 ; Show double ranges as "1-172" instead of "1-8 to 160-172"
  172. CompactAffixTypes = 1 ; Use compact affix type designations: Suffix = S, Prefix = P, Comp. Suffix = CS, Comp. Prefix = CP
  173.  
  174. MarkHighLinksAsValuable = 1 ; Mark rares or uniques with 5L or 6L as valuable.
  175.  
  176. MirrorAffixLines = 1 ; Show a copy of the affix line in question when showing affix details.
  177. ;
  178. ; For example, would display "Prefix, 5-250" instead of "+246 to Accuracy Rating, Prefix, 5-250".
  179. ; Since the affixes are processed in order one can attribute which is which to the ordering of
  180. ; the lines in the tooltip to the item data in game.
  181.  
  182. MirrorLineFieldWidth = 18 ; Mirrored affix line width. Set to a number above 0 to truncate (or pad) to this many characters.
  183. ; Appends AffixDetailEllipsis when truncating.
  184. ValueRangeFieldWidth = 7 ; Width of field that displays the affix' value range(s). Set to a number larger than 0 to truncate (or pad) to this many characters.
  185. ;
  186. ; Keep in mind that there are sometimes double ranges to be displayed. Like for example on an axe, implicit physical damage might
  187. ; have a lower bound range and a upper bound range. In this case the lower bound range can have at most a 3 digit minimum value,
  188. ; and at most a 3 digit maximum value. To then display just the lower bound (which constitutes one value range field), you would need
  189. ; at least 7 characters (ex: 132-179). To complete the example here is how it would look like with 2 fields (lower and upper bound)
  190. ; 132-179 168-189. Note that you don't need to set 15 as option value to display both fields correctly. As the name implies the option
  191. ; is per field, so a value of 8 can display two 8 character wide fields correctly.
  192.  
  193. AffixDetailDelimiter := " " ; Field delimiter for affix detail lines. This is put between value range fields. If this value were set to a comma, the above
  194. ; double range example would become 132-179,168-189.
  195.  
  196. AffixDetailEllipsis := "…" ; If the MirrorLineFieldWidth is set to a value that is smaller than the actual length of the affix line text
  197. ; the affix line will be cut off and this text will be appended at the end to indicate tha the line was truncated.
  198. ;
  199. ; Usually this is set to the ASCII or Unicode value of the three dot ellipsis (alt code: 0133).
  200. ; Note that the correct display of text characters outside the ASCII standard depend on the file encoding and the
  201. ; AHK version used. For best results, save this file as ANSI encoding which can be read and displayed correctly by
  202. ; either ANSI based AutoHotkey or Unicode based AutoHotkey.
  203. ;
  204. ; Example: assume the affix line to be mirrored is '+#% increased Spell Damage'.
  205. ; If the MirrorLineFieldWidth is set to 18, this field would be shown as '+#% increased Spel…'
  206.  
  207. PutResultsOnClipboard = 0 ; Put result text on clipboard (overwriting the textual representation the game put there to begin with)
  208.  
  209. ; Pixels mouse must move to auto-dismiss tooltip
  210. MouseMoveThreshold := 40
  211.  
  212. ; Set this to 1 if you want to have the tooltip disappear after the time frame set below.
  213. ; Otherwise you will have to move the mouse by 5 pixels for the tip to disappear.
  214. UseTooltipTimeout = 0
  215.  
  216. ;How many ticks to wait before removing tooltip. 1 tick = 100ms. Example, 50 ticks = 5secends, 75 Ticks = 7.5Secends
  217. ToolTipTimeoutTicks := 150
  218.  
  219. ; Font size for the tooltip, leave empty for default
  220. FontSize := 11
  221.  
  222. ; OPTIONS END
  223.  
  224. ; Menu tooltip
  225. Menu, tray, Tip, Path of Exile Item Info 1.7.5
  226.  
  227. ; Windows system tray icon
  228. ; possible values: poe.ico, poe-bw.ico, poe-web.ico, info.ico
  229. Menu, tray, Icon, data\poe-bw.ico
  230.  
  231. If (A_AhkVersion <= "1.0.45")
  232. {
  233. msgbox, You need AutoHotkey v1.0.45 or later to run this script. `n`nPlease go to http://ahkscript.org/download and download a recent version.
  234. exit
  235. }
  236.  
  237. IfNotExist, %A_ScriptDir%\data
  238. {
  239. msgbox, Error 37`n`n"data" directory not found at "%A_ScriptDir%".`n`nPlease make sure the data directory is present at the same location where you are executing the script from.
  240. exit
  241. }
  242.  
  243. #Include %A_ScriptDir%\data\MapList.txt
  244.  
  245. MsgUnhandled := "Unhandled case. Please report the item that you are inspecting by pasting the textual item representation that is on your clipboard right now into a reply to the script's forum thread at http://www.pathofexile.com/forum/view-thread/790438.`n`nThanks so much for helping out!"
  246.  
  247. ; Create font for later use
  248. FixedFont := CreateFont()
  249.  
  250. ; Creates a font for later use
  251. CreateFont()
  252. {
  253. Global FontSize
  254. Options :=
  255. If (!(FontSize = ""))
  256. {
  257. Options = s%FontSize%
  258. }
  259. Gui Font, %Options%, Courier New
  260. Gui Font, %Options%, Consolas
  261. Gui Add, Text, HwndHidden,
  262. SendMessage, 0x31,,,, ahk_id %Hidden%
  263. return ErrorLevel
  264. }
  265.  
  266. ; Sets the font for a created ahk tooltip
  267. SetFont(Font)
  268. {
  269. SendMessage, 0x30, Font, 1,, ahk_class tooltips_class32 ahk_exe autohotkey.exe
  270. }
  271.  
  272. ParseElementalDamage(String, DmgType, ByRef DmgLo, ByRef DmgHi)
  273. {
  274. IfInString, String, %DmgType% Damage
  275. {
  276. IfInString, String, Converted to or IfInString, String, taken as
  277. return
  278. IfNotInString, String, increased
  279. {
  280. StringSplit, Arr, String, %A_Space%
  281. StringSplit, Arr, Arr2, -
  282. DmgLo := Arr1
  283. DmgHi := Arr2
  284. }
  285. }
  286. }
  287.  
  288. ; Function that checks item type name against entries
  289. ; from ItemList.txt to get the item's base level
  290. ; Added by kongyuyu, changed by hazydoc
  291. CheckBaseLevel(ItemTypeName)
  292. {
  293. ItemListArray = 0
  294. Loop, Read, %A_WorkingDir%\data\ItemList.txt
  295. {
  296. ; This loop retrieves each line from the file, one at a time.
  297. ItemListArray += 1 ; Keep track of how many items are in the array.
  298. StringSplit, NameLevel, A_LoopReadLine, |,
  299. Array%ItemListArray%1 := NameLevel1 ; Store this line in the next array element.
  300. Array%ItemListArray%2 := NameLevel2
  301. }
  302.  
  303. Loop %ItemListArray% {
  304. element := Array%A_Index%1
  305. If(ItemTypeName == element)
  306. {
  307. BaseLevel := Array%A_Index%2
  308. Break
  309. }
  310. }
  311. return BaseLevel
  312. }
  313.  
  314. CheckRarityLevel(RarityString)
  315. {
  316. IfInString, RarityString, Normal
  317. return 1
  318. IfInString, RarityString, Magic
  319. return 2
  320. IfInString, RarityString, Rare
  321. return 3
  322. IfInString, RarityString, Unique
  323. return 4
  324. return 0 ; unknown rarity. shouldn't happen!
  325. }
  326.  
  327. ParseItemType(ItemDataStats, ItemDataNamePlate, ByRef BaseType, ByRef SubType, ByRef GripType)
  328. {
  329. ; Grip type only matters for weapons at this point. For all others it will be 'None'.
  330. GripType = None
  331.  
  332. ; Check stats section first as weapons usually have their sub type as first line
  333. Loop, Parse, ItemDataStats, `n, `r
  334. {
  335. IfInString, A_LoopField, One Handed Axe
  336. {
  337. BaseType = Weapon
  338. SubType = Axe
  339. GripType = 1H
  340. return
  341. }
  342. IfInString, A_LoopField, Two Handed Axe
  343. {
  344. BaseType = Weapon
  345. SubType = Axe
  346. GripType = 2H
  347. return
  348. }
  349. IfInString, A_LoopField, One Handed Mace
  350. {
  351. BaseType = Weapon
  352. SubType = Mace
  353. GripType = 1H
  354. return
  355. }
  356. IfInString, A_LoopField, Two Handed Mace
  357. {
  358. BaseType = Weapon
  359. SubType = Mace
  360. GripType = 2H
  361. return
  362. }
  363. IfInString, A_LoopField, Sceptre
  364. {
  365. BaseType = Weapon
  366. SubType = Sceptre
  367. GripType = 1H
  368. return
  369. }
  370. IfInString, A_LoopField, Staff
  371. {
  372. BaseType = Weapon
  373. SubType = Staff
  374. GripType = 2H
  375. return
  376. }
  377. IfInString, A_LoopField, One Handed Sword
  378. {
  379. BaseType = Weapon
  380. SubType = Sword
  381. GripType = 1H
  382. return
  383. }
  384. IfInString, A_LoopField, Two Handed Sword
  385. {
  386. BaseType = Weapon
  387. SubType = Sword
  388. GripType = 2H
  389. return
  390. }
  391. IfInString, A_LoopField, Dagger
  392. {
  393. BaseType = Weapon
  394. SubType = Dagger
  395. GripType = 1H
  396. return
  397. }
  398. IfInString, A_LoopField, Claw
  399. {
  400. BaseType = Weapon
  401. SubType = Claw
  402. GripType = 1H
  403. return
  404. }
  405. IfInString, A_LoopField, Bow
  406. {
  407. ; Not really sure if I should classify bow as 2H (because that would make sense)
  408. ; but you can equip a quiver in 2nd hand slot, so it could be 1H?
  409. BaseType = Weapon
  410. SubType = Bow
  411. GripType = 1H
  412. return
  413. }
  414. IfInString, A_LoopField, Wand
  415. {
  416. BaseType = Weapon
  417. SubType = Wand
  418. GripType = 1H
  419. return
  420. }
  421. }
  422.  
  423. ; Check name plate section
  424. Loop, Parse, ItemDataNamePlate, `n, `r
  425. {
  426. ; a few cases that cause incorrect id later
  427. ; and thus should come first
  428. ; Note: still need to work on proper id for
  429. ; all armour types.
  430. IfInString, A_LoopField, Ringmail
  431. {
  432. BaseType = Armour
  433. SubType = BodyArmour
  434. return
  435. }
  436. IfInString, A_LoopField, Mantle
  437. {
  438. BaseType = Armour
  439. SubType = BodyArmour
  440. return
  441. }
  442. IfInString, A_LoopField, Shell
  443. {
  444. BaseType = Armour
  445. SubType = BodyArmour
  446. return
  447. }
  448.  
  449. ; Belts, Amulets, Rings, Quivers, Flasks
  450. IfInString, A_LoopField, Rustic Sash
  451. {
  452. BaseType = Item
  453. SubType = Belt
  454. return
  455. }
  456. IfInString, A_LoopField, Belt
  457. {
  458. BaseType = Item
  459. SubType = Belt
  460. return
  461. }
  462. IfInString, A_LoopField, Amulet
  463. {
  464. BaseType = Item
  465. SubType = Amulet
  466. return
  467. }
  468. IfInString, A_LoopField, Ring
  469. {
  470. BaseType = Item
  471. SubType = Ring
  472. return
  473. }
  474. IfInString, A_LoopField, Quiver
  475. {
  476. BaseType = Item
  477. SubType = Quiver
  478. return
  479. }
  480. IfInString, A_LoopField, Flask
  481. {
  482. BaseType = Item
  483. SubType = Flask
  484. return
  485. }
  486. IfInString, A_LoopField, %A_Space%Map
  487. {
  488. BaseType = Map
  489. global matchList
  490. Loop % matchList.MaxIndex()
  491. {
  492. Match := matchList[A_Index]
  493. IfInString, A_LoopField, %Match%
  494. {
  495. SubType = %Match%
  496. return
  497. }
  498. }
  499.  
  500. SubType = Unknown%A_Space%Map
  501. return
  502. }
  503. ; Dry Peninsula fix
  504. IfInString, A_LoopField, Dry%A_Space%Peninsula
  505. {
  506. BaseType = Map
  507. SubType = Dry%A_Space%Peninsula
  508. return
  509. }
  510.  
  511. ; Shields
  512. IfInString, A_LoopField, Shield
  513. {
  514. BaseType = Armour
  515. SubType = Shield
  516. return
  517. }
  518. IfInString, A_LoopField, Buckler
  519. {
  520. BaseType = Armour
  521. SubType = Shield
  522. return
  523. }
  524. IfInString, A_LoopField, Bundle
  525. {
  526. BaseType = Armour
  527. SubType = Shield
  528. return
  529. }
  530. IfInString, A_LoopField, Gloves
  531. {
  532. BaseType = Armour
  533. SubType = Gloves
  534. return
  535. }
  536. IfInString, A_LoopField, Mitts
  537. {
  538. BaseType = Armour
  539. SubType = Gloves
  540. return
  541. }
  542. IfInString, A_LoopField, Gauntlets
  543. {
  544. BaseType = Armour
  545. SubType = Gloves
  546. return
  547. }
  548.  
  549. ; Helmets
  550. IfInString, A_LoopField, Helmet
  551. {
  552. BaseType = Armour
  553. SubType = Helmet
  554. return
  555. }
  556. IfInString, A_LoopField, Helm
  557. {
  558. BaseType = Armour
  559. SubType = Helmet
  560. return
  561. }
  562. If (InStr(A_LoopField, "Hat") AND (Not InStr(A_LoopField, "Hate")))
  563. {
  564. BaseType = Armour
  565. SubType = Helmet
  566. return
  567. }
  568. IfInString, A_LoopField, Mask
  569. {
  570. BaseType = Armour
  571. SubType = Helmet
  572. return
  573. }
  574. IfInString, A_LoopField, Hood
  575. {
  576. BaseType = Armour
  577. SubType = Helmet
  578. return
  579. }
  580. IfInString, A_LoopField, Ursine Pelt
  581. {
  582. BaseType = Armour
  583. SubType = Helmet
  584. return
  585. }
  586. IfInString, A_LoopField, Lion Pelt
  587. {
  588. BaseType = Armour
  589. SubType = Helmet
  590. return
  591. }
  592. IfInString, A_LoopField, Circlet
  593. {
  594. BaseType = Armour
  595. SubType = Helmet
  596. return
  597. }
  598. IfInString, A_LoopField, Sallet
  599. {
  600. BaseType = Armour
  601. SubType = Helmet
  602. return
  603. }
  604. IfInString, A_LoopField, Burgonet
  605. {
  606. BaseType = Armour
  607. SubType = Helmet
  608. return
  609. }
  610. IfInString, A_LoopField, Bascinet
  611. {
  612. BaseType = Armour
  613. SubType = Helmet
  614. return
  615. }
  616. IfInString, A_LoopField, Crown
  617. {
  618. BaseType = Armour
  619. SubType = Helmet
  620. return
  621. }
  622. IfInString, A_LoopField, Cage
  623. {
  624. BaseType = Armour
  625. SubType = Helmet
  626. return
  627. }
  628. IfInString, A_LoopField, Tricorne
  629. {
  630. BaseType = Armour
  631. SubType = Helmet
  632. return
  633. }
  634.  
  635. ; Boots
  636. IfInString, A_LoopField, Boots
  637. {
  638. BaseType = Armour
  639. SubType = Boots
  640. return
  641. }
  642. IfInString, A_LoopField, Greaves
  643. {
  644. BaseType = Armour
  645. SubType = Boots
  646. return
  647. }
  648. IfInString, A_LoopField, Slippers
  649. {
  650. BaseType = Armour
  651. SubType = Boots
  652. return
  653. }
  654. }
  655.  
  656. ; TODO: need a reliable way to determine sub type for armour
  657. ; right now it's just determine anything else first if it's
  658. ; not that, it's armour.
  659. BaseType = Armour
  660. SubType = Armour
  661. }
  662.  
  663. GetClipboardContents(DropNewlines = False)
  664. {
  665. Result =
  666. If Not DropNewlines
  667. {
  668. Loop, Parse, Clipboard, `n, `r
  669. {
  670. Result := Result . A_LoopField . "`r`n"
  671. }
  672. }
  673. Else
  674. {
  675. Loop, Parse, Clipboard, `n, `r
  676. {
  677. Result := Result . A_LoopField
  678. }
  679. }
  680. return Result
  681. }
  682.  
  683. SetClipboardContents(String)
  684. {
  685. Clipboard := String
  686. }
  687.  
  688. ; attempted to create a nice re-usable function for all the string splitting
  689. ; doesn't work correctly yet!
  690. SplitString(StrInput, StrDelimiter)
  691. {
  692. TempDelim := "``"
  693. StringReplace, TempResult, StrInput, %StrDelimiter%, %TempDelim%, All
  694. StringSplit, Parts, TempResult, %TempDelim%
  695. return Parts
  696. }
  697.  
  698. ; Look up just the most applicable bracket for an affix.
  699. ; Most applicable means Value is between bounds of bracket range
  700. ; OR highest entry possible given the item level
  701. ; returns: "#-#" format range
  702. ; If Value is unspecified ("") return the max possible bracket
  703. ; based on item level
  704. LookupAffixBracket(Filename, ItemLevel, Value="", ByRef BracketLevel="")
  705. {
  706. AffixLevel := 0
  707. AffixDataIndex := 0
  708. If (Not Value == "")
  709. {
  710. ValueLo := Value ; value from ingame tooltip
  711. ValueHi := Value ; for single values (which most of them are) ValueLo == ValueHi
  712. ParseRange(Value, ValueHi, ValueLo)
  713. }
  714. ; msgbox, Filename: %Filename%`, Value: %Value%`, ValueLo: %ValueLo%`, ValueHi: %ValueHi%
  715. LookupIsDoubleRange := False ; for affixes like "Adds +# ... Damage" which have a lower AND an upper bound range
  716. BracketRange := "n/a"
  717. Loop, Read, %A_WorkingDir%\%Filename%
  718. {
  719. AffixDataIndex += 1
  720. StringSplit, AffixDataParts, A_LoopReadLine, |,
  721. RangeLevel := AffixDataParts1
  722. RangeValues := AffixDataParts2
  723. If (RangeLevel > ItemLevel)
  724. {
  725. Break
  726. }
  727. IfInString, RangeValues, `,
  728. {
  729. LookupIsDoubleRange := True
  730. }
  731. If (LookupIsDoubleRange)
  732. {
  733. ; example lines from txt file database for double range lookups:
  734. ; 3|1,14-15
  735. ; 13|1-3,35-37
  736. StringSplit, DoubleRangeParts, RangeValues, `,
  737. LB := DoubleRangeParts%DoubleRangeParts%1
  738. UB := DoubleRangeParts%DoubleRangeParts%2
  739. ; default case: lower bound is single value: #
  740. ; see level 3 case in example lines above
  741. LBMin := LB
  742. LBMax := LB
  743. UBMin := UB
  744. UBMax := UB
  745. IfInString, LB, -
  746. {
  747. ; lower bound is a range: #-#
  748. ParseRange(LB, LBMax, LBMin)
  749. }
  750. IfInString, UB, -
  751. {
  752. ParseRange(UB, UBMax, UBMin)
  753. }
  754. LBPart = %LBMin%
  755. UBPart = %UBMax%
  756. ; record bracket range if it is within bounds of the text file entry
  757. If (Value == "" or (((ValueLo >= LBMin) and (ValueLo <= LBMax)) and ((ValueHi >= UBMin) and (ValueHi <= UBMax))))
  758. {
  759. BracketRange = %LBPart%-%UBPart%
  760. AffixLevel = %RangeLevel%
  761. }
  762. }
  763. Else
  764. {
  765. ParseRange(RangeValues, HiVal, LoVal)
  766. ; record bracket range if it is within bounds of the text file entry
  767. If (Value == "" or ((ValueLo >= LoVal) and (ValueHi <= HiVal)))
  768. {
  769. BracketRange = %LoVal%-%HiVal%
  770. AffixLevel = %RangeLevel%
  771. }
  772. }
  773. }
  774. BracketLevel := AffixLevel
  775. return BracketRange
  776. }
  777.  
  778. ; Look up complete data for an affix. Depending on settings flags
  779. ; this may include many things, and will return a string used for
  780. ; end user display rather than further calculations.
  781. ; Use LookupAffixBracket if you need a range format to do calculations with.
  782. LookupAffixData(Filename, ItemLevel, Value, ByRef BracketLevel="", ByRef Tier=0)
  783. {
  784. Global MaxLevel
  785. Global MaxSpanStartingFromFirst
  786. Global CompactDoubleRanges
  787. Global TierRelativeToItemLevel
  788. MaxLevel := 0
  789. AffixLevel := 0
  790. AffixDataIndex := 0
  791. ValueLo := Value ; value from ingame tooltip
  792. ValueHi := Value ; for single values (which most of them are) ValueLo == ValueHi
  793. ValueIsMinMax := False ; treat Value as min/max units (#-#) or as single unit (#)
  794. LookupIsDoubleRange := False ; for affixes like "Adds +# ... Damage" which have a lower AND an upper bound range
  795. FirstRangeValues =
  796. BracketRange := "n/a"
  797. MaxRange =
  798. FinalRange =
  799. MaxLevel := 1
  800. RangeLevel := 1
  801. Tier := 0
  802. MaxTier := 0
  803. IfInString, Value, -
  804. {
  805. ParseRange(Value, ValueHi, ValueLo)
  806. ValueIsMinMax := True
  807. }
  808. ; Pre-pass to determine max tier
  809. Loop, Read, %A_WorkingDir%\%Filename%
  810. {
  811. MaxTier += 1
  812. StringSplit, AffixDataParts, A_LoopReadLine, |,
  813. RangeLevel := AffixDataParts1
  814. If (TierRelativeToItemLevel AND (RangeLevel >= ItemLevel))
  815. {
  816. Break
  817. }
  818. }
  819. ;msgbox, MaxTier: %MaxTier%
  820. Loop, Read, %A_WorkingDir%\%Filename%
  821. {
  822. AffixDataIndex += 1
  823. StringSplit, AffixDataParts, A_LoopReadLine, |,
  824. RangeValues := AffixDataParts2
  825. RangeLevel := AffixDataParts1
  826. If (AffixDataIndex == 1)
  827. {
  828. FirstRangeValues := RangeValues
  829. }
  830. If (RangeLevel > ItemLevel)
  831. {
  832. Break
  833. }
  834. MaxLevel := RangeLevel
  835. IfInString, RangeValues, `,
  836. {
  837. LookupIsDoubleRange := True
  838. }
  839. If (LookupIsDoubleRange)
  840. {
  841. ; ; variables for min/max double ranges, like in the "Adds +# ... Damage" case
  842. ; Global LBMin ; (L)ower (B)ound minium value
  843. ; Global LBMax ; (L)ower (B)ound maximum value
  844. ; GLobal UBMin ; (U)pper (B)ound minimum value
  845. ; GLobal UBMax ; (U)pper (B)ound maximum value
  846. ; ; same, just for the first range's values
  847. ; Global FRLBMin
  848. ; Global FRLBMax
  849. ; Global FRUBMin
  850. ; Global FRUBMax
  851. ; example lines from txt file database for double range lookups:
  852. ; 3|1,14-15
  853. ; 13|1-3,35-37
  854. StringSplit, DoubleRangeParts, RangeValues, `,
  855. LB := DoubleRangeParts%DoubleRangeParts%1
  856. UB := DoubleRangeParts%DoubleRangeParts%2
  857. ; default case: lower bound is single value: #
  858. ; see level 3 case in example lines above
  859. LBMin := LB
  860. LBMax := LB
  861. UBMin := UB
  862. UBMax := UB
  863. IfInString, LB, -
  864. {
  865. ; lower bound is a range: #-#
  866. ParseRange(LB, LBMax, LBMin)
  867. }
  868. IfInString, UB, -
  869. {
  870. ParseRange(UB, UBMax, UBMin)
  871. }
  872. If (AffixDataIndex == 1)
  873. {
  874. StringSplit, FirstDoubleRangeParts, FirstRangeValues, `,
  875. FRLB := FirstDoubleRangeParts%FirstDoubleRangeParts%1
  876. FRUB := FirstDoubleRangeParts%FirstDoubleRangeParts%2
  877. ParseRange(FRUB, FRUBMax, FRUBMin)
  878. ParseRange(FRLB, FRLBMax, FRLBMin)
  879. }
  880. If ((LBMin == LBMax) or CompactDoubleRanges)
  881. {
  882. LBPart = %LBMin%
  883. }
  884. Else
  885. {
  886. LBPart = %LBMin%-%LBMax%
  887. }
  888. If ((UBMin == UBMax) or CompactDoubleRanges)
  889. {
  890. UBPart = %UBMax%
  891. }
  892. Else
  893. {
  894. UBPart = %UBMin%-%UBMax%
  895. }
  896. If ((FRLBMin == FRLBMax) or CompactDoubleRanges)
  897. {
  898. FRLBPart = %FRLBMin%
  899. }
  900. Else
  901. {
  902. FRLBPart = %FRLBMin%-%FRLBMax%
  903. }
  904. If (CompactDoubleRanges)
  905. {
  906. MiddlePart := "-"
  907. }
  908. Else
  909. {
  910. MiddlePart := " to "
  911. }
  912. ; record bracket range if it is withing bounds of the text file entry
  913. If (((ValueLo >= LBMin) and (ValueLo <= LBMax)) and ((ValueHi >= UBMin) and (ValueHi <= UBMax)))
  914. {
  915. ;msgbox, Value: %Value%`, LBPart: %LBPart%`, UBPart: %UBPart%
  916. BracketRange = %LBPart%%MiddlePart%%UBPart%
  917. AffixLevel = %MaxLevel%
  918. Tier := ((MaxTier - AffixDataIndex) + 1)
  919. ;msgbox, BracketRange: %BracketRange%
  920. }
  921. ; record max possible range regardless of within bounds
  922. If (MaxSpanStartingFromFirst)
  923. {
  924. MaxRange = %FRLBPart%%MiddlePart%%UBPart%
  925. }
  926. Else
  927. {
  928. MaxRange = %LBPart%%MiddlePart%%UBPart%
  929. }
  930. }
  931. Else
  932. {
  933. If (AffixDataIndex = 1)
  934. {
  935. ParseRange(FirstRangeValues, FRHiVal, FRLoVal)
  936. }
  937. ParseRange(RangeValues, HiVal, LoVal)
  938. ; record bracket range if it is within bounds of the text file entry
  939. If ((ValueLo >= LoVal) and (ValueHi <= HiVal))
  940. {
  941. If (LoVal = HiVal)
  942. {
  943. BracketRange = %LoVal%
  944. }
  945. Else
  946. {
  947. BracketRange = %LoVal%-%HiVal%
  948. }
  949. AffixLevel = %MaxLevel%
  950. Tier := ((MaxTier - AffixDataIndex) + 1)
  951. ;msgbox, AffixDataIndex: %AffixDataIndex%, FirstRangeValues: %FirstRangeValues%,
  952. }
  953. ; record max possible range regardless of within bounds
  954. If (MaxSpanStartingFromFirst)
  955. {
  956. MaxRange = %FRLoVal%-%HiVal%
  957. }
  958. Else
  959. {
  960. MaxRange = %LoVal%-%HiVal%
  961. }
  962. }
  963. ; msgbox, Filename: %Filename%`n ValueLo: %ValueLo%`, ValueHi: %ValueHi%`n LoVal: %LoVal%`, HiVal: %HiVal%
  964. }
  965. BracketLevel := AffixLevel
  966. FinalRange := AssembleValueRangeFields(BracketRange, BracketLevel, MaxRange, MaxLevel)
  967. ; msgbox, FinalRange: %FinalRange%
  968. return FinalRange
  969. }
  970.  
  971. AssembleValueRangeFields(BracketRange, BracketLevel, MaxRange="", MaxLevel=0)
  972. {
  973. Global ShowAffixLevel
  974. Global ShowAffixBracket
  975. Global ShowAffixMaxPossible
  976. Global ValueRangeFieldWidth
  977. Global AffixDetailDelimiter
  978. If (ShowAffixBracket)
  979. {
  980. FinalRange := BracketRange
  981. If (ValueRangeFieldWidth > 0)
  982. {
  983. FinalRange := StrPad(FinalRange, ValueRangeFieldWidth, "left")
  984. }
  985. If (ShowAffixLevel)
  986. {
  987. FinalRange := FinalRange . " " . "(" . BracketLevel . ")" . ", "
  988. }
  989. Else
  990. {
  991. FinalRange := FinalRange . AffixDetailDelimiter
  992. }
  993. }
  994. If (MaxRange and ShowAffixMaxPossible)
  995. {
  996. If (ValueRangeFieldWidth > 0)
  997. {
  998. MaxRange := StrPad(MaxRange, ValueRangeFieldWidth, "left")
  999. }
  1000. FinalRange := FinalRange . MaxRange
  1001. If (ShowAffixLevel)
  1002. {
  1003. FinalRange := FinalRange . " " . "(" . MaxLevel . ")"
  1004. }
  1005. }
  1006. return FinalRange
  1007. }
  1008.  
  1009. ParseRarity(ItemData_NamePlate)
  1010. {
  1011. Loop, Parse, ItemData_NamePlate, `n, `r
  1012. {
  1013. IfInString, A_LoopField, Rarity:
  1014. {
  1015. StringSplit, RarityParts, A_LoopField, %A_Space%
  1016. Break
  1017. }
  1018. }
  1019. return RarityParts%RarityParts%2
  1020. }
  1021.  
  1022. ParseQuality(ItemDataNamePlate)
  1023. {
  1024. ItemQuality := 0
  1025. Loop, Parse, ItemDataNamePlate, `n, `r
  1026. {
  1027. If (StrLen(A_LoopField) = 0)
  1028. {
  1029. Break
  1030. }
  1031. IfInString, A_LoopField, Unidentified
  1032. {
  1033. Break
  1034. }
  1035. IfInString, A_LoopField, Quality:
  1036. {
  1037. ItemQuality := RegExReplace(A_LoopField, "Quality: \+(\d+)% .*", "$1")
  1038. Break
  1039. }
  1040. }
  1041. return ItemQuality
  1042. }
  1043.  
  1044. ParseAugmentations(ItemDataChunk, ByRef AffixCSVList)
  1045. {
  1046. Global CurAugment
  1047. CurAugment := ItemDataChunk
  1048. Loop, Parse, ItemDataChunk, `n, `r
  1049. {
  1050. CurAugment := A_LoopField
  1051. IfInString, A_LoopField, Requirements:
  1052. {
  1053. Break
  1054. }
  1055. IfInString, A_LoopField, (augmented)
  1056. {
  1057. StringSplit, LineParts, A_LoopField, :
  1058. AffixCSVList := AffixCSVList . "'" . LineParts%LineParts%1 . "'"
  1059. AffixCSVList := AffixCSVList . ", "
  1060. }
  1061. }
  1062. AffixCSVList := SubStr(AffixCSVList, 1, -2)
  1063. }
  1064.  
  1065. ParseRequirements(ItemDataChunk, ByRef Level, ByRef Attributes, ByRef Values="")
  1066. {
  1067. IfNotInString, ItemDataChunk, Requirements
  1068. {
  1069. return
  1070. }
  1071. Attr =
  1072. AttrValues =
  1073. Delim := ","
  1074. DelimLen := StrLen(Delim)
  1075. Loop, Parse, ItemDataChunk, `n, `r
  1076. {
  1077. If StrLen(A_LoopField) = 0
  1078. {
  1079. Break ; not interested in blank lines
  1080. }
  1081. IfInString, A_LoopField, Str
  1082. {
  1083. Attr := Attr . "Str" . Delim
  1084. AttrValues := AttrValues . GetColonValue(A_LoopField) . Delim
  1085. }
  1086. IfInString, A_LoopField, Dex
  1087. {
  1088. Attr := Attr . "Dex" . Delim
  1089. AttrValues := AttrValues . GetColonValue(A_LoopField) . Delim
  1090. }
  1091. IfInString, A_LoopField, Int
  1092. {
  1093. Attr := Attr . "Int" . Delim
  1094. AttrValues := AttrValues . GetColonValue(A_LoopField) . Delim
  1095. }
  1096. IfInString, A_LoopField, Level
  1097. {
  1098. Level := GetColonValue(A_LoopField)
  1099. }
  1100. }
  1101. ; chop off last Delim
  1102. If (SubStr(Attr, -(DelimLen-1)) == Delim)
  1103. {
  1104. Attr := SubStr(Attr, 1, -(DelimLen))
  1105. }
  1106. If (SubStr(AttrValues, -(DelimLen-1)) == Delim)
  1107. {
  1108. AttrValues := SubStr(AttrValues, 1, -(DelimLen))
  1109. }
  1110. Attributes := Attr
  1111. Values := AttrValues
  1112. }
  1113.  
  1114. ; parses #low-#high and sets Hi to #high and Lo to #low
  1115. ; if RangeChunk is just a single value (#) it will set both
  1116. ; Hi and Lo to this single value (effectively making the range 1-1 if # was 1)
  1117. ParseRange(RangeChunk, ByRef Hi, ByRef Lo)
  1118. {
  1119. IfInString, RangeChunk, -
  1120. {
  1121. StringSplit, RangeParts, RangeChunk, -
  1122. Lo := RegExReplace(RangeParts1, "(\d+?)", "$1")
  1123. Hi := RegExReplace(RangeParts2, "(\d+?)", "$1")
  1124. }
  1125. Else
  1126. {
  1127. Hi := RangeChunk
  1128. Lo := RangeChunk
  1129. }
  1130. }
  1131.  
  1132. ParseItemLevel(ItemData, PartialString="Itemlevel:")
  1133. {
  1134. Result =
  1135. Loop, Parse, ItemData, `n, `r
  1136. {
  1137. If StrLen(A_LoopField) = 0
  1138. {
  1139. Break
  1140. }
  1141. IfInString, A_LoopField, %PartialString%
  1142. {
  1143. StringSplit, ItemLevelParts, A_LoopField, %A_Space%
  1144. Result := ItemLevelParts2
  1145. Break
  1146. }
  1147. }
  1148. return Result
  1149. }
  1150.  
  1151. StrMult(Char, Times)
  1152. {
  1153. Result =
  1154. Loop, %Times%
  1155. {
  1156. Result := Result . Char
  1157. }
  1158. return Result
  1159. }
  1160.  
  1161. StrTrimSpaceLeft(String)
  1162. {
  1163. return RegExReplace(String, " *(.+?)", "$1")
  1164. }
  1165.  
  1166. StrTrimSpaceRight(String)
  1167. {
  1168. return RegExReplace(String, "(.+?) *$", "$1")
  1169. }
  1170.  
  1171. StrTrimSpace(String)
  1172. {
  1173. return RegExReplace(String, " *(.+?) *", "$1")
  1174. }
  1175.  
  1176. ; Pads a string with a multiple of PadChar to become a wanted total length.
  1177. ; Note that Side is the side that is padded not the anchored side.
  1178. ; Meaning, if you pad right side, the text will move left. If Side was an
  1179. ; anchor instead, the text would move right if anchored right.
  1180. StrPad(String, Length, Side="right", PadChar=" ")
  1181. {
  1182. ; Result := String
  1183. StringLen, Len, String
  1184. AddLen := Length-Len
  1185. If (AddLen <= 0)
  1186. {
  1187. ; msgbox, String: %String%`, Length: %Length%`, Len: %Len%`, AddLen: %AddLen%
  1188. return String
  1189. }
  1190. Pad := StrMult(PadChar, AddLen)
  1191. If (Side == "right")
  1192. {
  1193. Result := String . Pad
  1194. }
  1195. Else
  1196. {
  1197. Result := Pad . String
  1198. }
  1199. return Result
  1200. }
  1201.  
  1202. ; estimate indicator, marks end user display values so they can take a look at it
  1203. MarkAsGuesstimate(ValueRange, Side="left", Indicator=" * ")
  1204. {
  1205. Global ValueRangeFieldWidth
  1206. Global MarkedAsGuess
  1207. MarkedAsGuess := True
  1208. return StrPad(ValueRange . Indicator, ValueRangeFieldWidth + StrLen(Indicator), Side)
  1209. }
  1210.  
  1211. MakeAffixDetailLine(AffixLine, AffixType, ValueRange, Tier)
  1212. {
  1213. Global ItemDataRarity
  1214. Delim := "|"
  1215. Ellipsis := AffixDetailEllipsis
  1216. Line := AffixLine . Delim . ValueRange . Delim . AffixType
  1217. If (ItemDataRarity == "Rare")
  1218. {
  1219. Line := Line . Delim . Tier
  1220. }
  1221. return Line
  1222. }
  1223.  
  1224. AppendAffixInfo(Line, AffixPos)
  1225. {
  1226. Global
  1227. AffixLines%AffixPos% := Line
  1228. }
  1229.  
  1230. AssembleAffixDetails()
  1231. {
  1232. Global
  1233. Local Result
  1234. Local Delim
  1235. Local Ellipsis
  1236. Local CurLine
  1237. Local IsImplicitMod
  1238. Local TierString
  1239. Local ValueRangeString
  1240. AffixLine =
  1241. AffixType =
  1242. ValueRange =
  1243. AffixTier =
  1244. Loop, %NumAffixLines%
  1245. {
  1246. CurLine := AffixLines%A_Index%
  1247. ; blank out affix line parts so that when affix line splits
  1248. ; into less parts than before, there won't be left overs
  1249. Loop, 3
  1250. {
  1251. AffixLineParts%A_Index% =
  1252. }
  1253. StringSplit, AffixLineParts, CurLine, |
  1254. AffixLine := AffixLineParts1
  1255. ValueRange := AffixLineParts2
  1256. AffixType := AffixLineParts3
  1257. AffixTier := AffixLineParts4
  1258.  
  1259. ;msgbox, AffixTier: %AffixTier%
  1260.  
  1261. Delim := AffixDetailDelimiter
  1262. Ellipsis := AffixDetailEllipsis
  1263.  
  1264. If (ValueRangeFieldWidth > 0)
  1265. {
  1266. ValueRange := StrPad(ValueRange, ValueRangeFieldWidth, "left")
  1267. }
  1268. If (MirrorAffixLines = 1)
  1269. {
  1270. If (MirrorLineFieldWidth > 0)
  1271. {
  1272. If(StrLen(AffixLine) > MirrorLineFieldWidth)
  1273. {
  1274. AffixLine := StrTrimSpaceRight(SubStr(AffixLine, 1, MirrorLineFieldWidth)) . Ellipsis
  1275. }
  1276. AffixLine := StrPad(AffixLine, MirrorLineFieldWidth + StrLen(Ellipsis))
  1277. }
  1278. ProcessedLine := AffixLine . Delim
  1279. }
  1280. IfInString, ValueRange, *
  1281. {
  1282. ValueRangeString := StrPad(ValueRange, (ValueRangeFieldWidth * 2) + (StrLen(AffixDetailDelimiter)))
  1283. }
  1284. Else
  1285. {
  1286. ValueRangeString := ValueRange
  1287. }
  1288. ProcessedLine := ProcessedLine . ValueRangeString . Delim
  1289. If (ShowAffixBracketTier == 1 AND Not (ItemDataRarity == "Unique"))
  1290. {
  1291. If (InStr(ValueRange, "*") AND ShowAffixBracketTier)
  1292. {
  1293. TierString := " "
  1294. }
  1295. Else
  1296. {
  1297. TierString := StrPad("T" . AffixTier, 3, "left")
  1298. }
  1299. ProcessedLine := ProcessedLine . TierString . Delim
  1300. }
  1301. ProcessedLine := ProcessedLine . AffixType . Delim
  1302. Result := Result . "`n" . ProcessedLine
  1303. }
  1304. ; msgbox, Result: %Result%
  1305. return Result
  1306. }
  1307.  
  1308. ; Same as AdjustRangeForQuality, except that Value is just
  1309. ; a single value and not a range.
  1310. AdjustValueForQuality(Value, ItemQuality, Direction="up")
  1311. {
  1312. If (ItemQuality < 1)
  1313. return Value
  1314. Divisor := ItemQuality / 100
  1315. If (Direction == "up")
  1316. {
  1317. Result := Round(Value + (Value * Divisor))
  1318. }
  1319. Else
  1320. {
  1321. Result := Round(Value - (Value * Divisor))
  1322. }
  1323. return Result
  1324. }
  1325.  
  1326. ; Adjust an affix' range for +% Quality on an item.
  1327. ; For example: given the range 10-20 and item quality +15%
  1328. ; the result would be 11.5-23 which is currently rounded up
  1329. ; to 12-23. Note that Direction does not play a part in rounding
  1330. ; rather it controls if adjusting up towards quality increase or
  1331. ; down from quality increase (to get the original value back)
  1332. AdjustRangeForQuality(ValueRange, ItemQuality, Direction="up")
  1333. {
  1334. If (ItemQuality = 0)
  1335. {
  1336. return ValueRange
  1337. }
  1338. VRHi := 0
  1339. VRLo := 0
  1340. ParseRange(ValueRange, VRHi, VRLo)
  1341. Divisor := ItemQuality / 100
  1342. If (Direction == "up")
  1343. {
  1344. VRHi := Round(VRHi + (VRHi * Divisor))
  1345. VRLo := Round(VRLo + (VRLo * Divisor))
  1346. }
  1347. Else
  1348. {
  1349. VRHi := Round(VRHi - (VRHi * Divisor))
  1350. VRLo := Round(VRLo - (VRLo * Divisor))
  1351. }
  1352. If (VRLo == VRHi)
  1353. {
  1354. ValueRange = %VRLo%
  1355. }
  1356. Else
  1357. {
  1358. ValueRange = %VRLo%-%VRHi%
  1359. }
  1360. return ValueRange
  1361. }
  1362.  
  1363. ; checks ActualValue against ValueRange, returning 1
  1364. ; if ActualValue is within bounds of ValueRange, 0 otherwise
  1365. WithinBounds(ValueRange, ActualValue)
  1366. {
  1367. ; msgbox, ValueRange: %ValueRange%`, ActualValue: %ActualValue%
  1368. VHi := 0
  1369. VLo := 0
  1370. ParseRange(ValueRange, VHi, VLo)
  1371. Result := 1
  1372. IfInString, ActualValue, -
  1373. {
  1374. AVHi := 0
  1375. AVLo := 0
  1376. ParseRange(ActualValue, AVHi, AVLo)
  1377. If ((AVLo < VLo) or (AVHi > VHi))
  1378. {
  1379. Result := 0
  1380. }
  1381. }
  1382. Else
  1383. {
  1384. If ((ActualValue < VLo) or (ActualValue > VHi))
  1385. {
  1386. Result := 0
  1387. }
  1388. }
  1389. ; msgbox, Result: %Result%
  1390. return Result
  1391. }
  1392.  
  1393. GetAffixTypeFromProcessedLine(PartialAffixString)
  1394. {
  1395. Global
  1396. Loop, %NumAffixLines%
  1397. {
  1398. Local AffixLine
  1399. AffixLine := AffixLines%A_Index%
  1400. IfInString, AffixLine, %PartialAffixString%
  1401. {
  1402. Local AffixLineParts
  1403. StringSplit, AffixLineParts, AffixLine, |
  1404. return AffixLineParts3
  1405. }
  1406. }
  1407. }
  1408.  
  1409. ; Get actual value from a line of the ingame tooltip as a number
  1410. ; that can be used in calculations.
  1411. GetActualValue(ActualValueLine)
  1412. {
  1413. Result := RegExReplace(ActualValueLine, ".*?\+?(\d+(?:-\d+|\.\d+)?).*", "$1")
  1414. return Result
  1415. }
  1416.  
  1417. ; Get value from a color line, e.g. given the line "Level: 57", returns the number 57
  1418. GetColonValue(Line)
  1419. {
  1420. IfInString, Line, :
  1421. {
  1422. StringSplit, LineParts, Line, :
  1423. Result := StrTrimSpace(LineParts%LineParts%2)
  1424. return Result
  1425. }
  1426. }
  1427.  
  1428. RangeMid(Range)
  1429. {
  1430. If (Range = 0 or Range = "0" or Range = "0-0")
  1431. {
  1432. return 0
  1433. }
  1434. RHi := 0
  1435. RLo := 0
  1436. ParseRange(Range, RHi, RLo)
  1437. RSum := RHi+RLo
  1438. If (RSum == 0)
  1439. {
  1440. return 0
  1441. }
  1442. return Floor((RHi+RLo)/2)
  1443. }
  1444.  
  1445. RangeMin(Range)
  1446. {
  1447. If (Range = 0 or Range = "0" or Range = "0-0")
  1448. {
  1449. return 0
  1450. }
  1451. RHi := 0
  1452. RLo := 0
  1453. ParseRange(Range, RHi, RLo)
  1454. return RLo
  1455. }
  1456.  
  1457. RangeMax(Range)
  1458. {
  1459. If (Range = 0 or Range = "0" or Range = "0-0")
  1460. {
  1461. return 0
  1462. }
  1463. RHi := 0
  1464. RLo := 0
  1465. ParseRange(Range, RHi, RLo)
  1466. return RHi
  1467. }
  1468.  
  1469. AddRange(Range1, Range2)
  1470. {
  1471. R1Hi := 0
  1472. R1Lo := 0
  1473. R2Hi := 0
  1474. R2Lo := 0
  1475. ParseRange(Range1, R1Hi, R1Lo)
  1476. ParseRange(Range2, R2Hi, R2Lo)
  1477. FinalHi := R1Hi + R2Hi
  1478. FinalLo := R1Lo + R2Lo
  1479. FinalRange = %FinalLo%-%FinalHi%
  1480. return FinalRange
  1481. }
  1482.  
  1483. ; used to check return values from LookupAffixBracket()
  1484. IsValidBracket(Bracket)
  1485. {
  1486. If (Bracket == "n/a")
  1487. {
  1488. return False
  1489. }
  1490. return True
  1491. }
  1492.  
  1493. ; used to check return values from LookupAffixData()
  1494. IsValidRange(Bracket)
  1495. {
  1496. IfInString, Bracket, n/a
  1497. {
  1498. return False
  1499. }
  1500. return True
  1501. }
  1502.  
  1503. ; Note that while ExtractCompAffixBalance() can be run on processed data
  1504. ; that has compact affix type declarations (or not) for this function to
  1505. ; work properly, make sure to run it on data that has compact affix types
  1506. ; turned off. The reason being that it is hard to count prefixes by there
  1507. ; being a "P" in a line that also has mirrored affix descriptions.
  1508. ExtractTotalAffixBalance(ProcessedData, ByRef Prefixes, ByRef Suffixes, ByRef CompPrefixes, ByRef CompSuffixes)
  1509. {
  1510. ; msgbox, ProcessedData: %ProcessedData%
  1511. Loop, Parse, ProcessedData, `n, `r
  1512. {
  1513. AffixLine := A_LoopField
  1514. IfInString, AffixLine, Comp. Prefix
  1515. {
  1516. CompPrefixes += 1
  1517. }
  1518. IfInString, AffixLine, Comp. Suffix
  1519. {
  1520. CompSuffixes += 1
  1521. }
  1522. }
  1523. ProcessedData := RegExReplace(ProcessedData, "Comp\. Prefix", "")
  1524. ProcessedData := RegExReplace(ProcessedData, "Comp\. Suffix", "")
  1525. ; msgbox, ProcessedData: %ProcessedData%
  1526. Loop, Parse, ProcessedData, `n, `r
  1527. {
  1528. AffixLine := A_LoopField
  1529. IfInString, AffixLine, Prefix
  1530. {
  1531. Prefixes += 1
  1532. ; ProcessedData := RegExReplace(ProcessedData, "Prefix", "")
  1533. }
  1534. IfInString, AffixLine, Suffix
  1535. {
  1536. Suffixes += 1
  1537. ; ProcessedData := RegExReplace(ProcessedData, "Suffix", "")
  1538. }
  1539. }
  1540. }
  1541. ExtractCompositeAffixBalance(ProcessedData, ByRef CompPrefixes, ByRef CompSuffixes)
  1542. {
  1543. Loop, Parse, ProcessedData, `n, `r
  1544. {
  1545. AffixLine := A_LoopField
  1546. IfInString, AffixLine, Comp. Prefix
  1547. {
  1548. CompPrefixes += 1
  1549. }
  1550. IfInString, AffixLine, Comp. Suffix
  1551. {
  1552. CompSuffixes += 1
  1553. }
  1554. }
  1555. }
  1556.  
  1557. ParseAffixes(ItemDataChunk, ItemLevel, ItemQuality, ByRef NumPrefixes, ByRef NumSuffixes)
  1558. {
  1559. Global ItemBaseType
  1560. Global ItemSubType
  1561. Global ItemGripType
  1562. Global NumAffixLines
  1563. Global ValueRangeFieldWidth ; for StrPad on guesstimated values
  1564. Global MsgUnhandled
  1565. Global MarkedAsGuess
  1566.  
  1567. ; keeps track of how many affix lines we have so they can be assembled later
  1568. ; acts as a loop index variable when iterating each affix data part
  1569. NumAffixLines := 0
  1570. NumPrefixes := 0
  1571. NumSuffixes := 0
  1572.  
  1573. ; Composition flags
  1574. ; these are required for later descision making when guesstimating
  1575. ; sources for parts of a value from composite and/or same name affixes
  1576. ; They will be set to the line number where they occur in the pre-pass
  1577. ; loop so that details for that line can be changed later after we
  1578. ; have more clues for possible compositions.
  1579. HasIIQ := 0
  1580. HasIncrArmour := 0
  1581. HasIncrEvasion := 0
  1582. HasIncrEnergyShield := 0
  1583. HasHybridDefences := 0
  1584. HasIncrArmourAndES := 0
  1585. HasIncrArmourAndEvasion := 0
  1586. HasIncrEvasionAndES := 0
  1587. HasIncrLightRadius := 0
  1588. HasIncrAccuracyRating := 0
  1589. HasIncrPhysDmg := 0
  1590. HasToAccuracyRating := 0
  1591. HasStunRecovery := 0
  1592. HasSpellDamage := 0
  1593. HasMaxMana := 0
  1594.  
  1595. ; max mana already accounted for in case of composite prefix+prefix "Spell Damage / Max Mana" + "Max Mana"
  1596. MaxManaPartial =
  1597.  
  1598. ; Accuracy Rating already accounted for in case of
  1599. ; composite prefix + composite suffix: "increased Physical Damage / to Accuracy Rating" + "to Accuracy Rating / Light Radius"
  1600. ; composite prefix + suffix: "increased Physical Damage / to Accuracy Rating" + "to Accuracy Rating"
  1601. ARPartial =
  1602. ARAffixTypePartial =
  1603.  
  1604. ; Partial for Block and Stun Recovery
  1605. BSRecPartial =
  1606.  
  1607. ; --- PRE-PASS ---
  1608.  
  1609. ; to determine composition flags
  1610. Loop, Parse, ItemDataChunk, `n, `r
  1611. {
  1612. If StrLen(A_LoopField) = 0
  1613. {
  1614. Break ; not interested in blank lines
  1615. }
  1616. IfInString, ItemDataChunk, Unidentified
  1617. {
  1618. Break ; not interested in unidentified items
  1619. }
  1620.  
  1621. NumAffixLines += 1
  1622.  
  1623. IfInString, A_LoopField, increased Light Radius
  1624. {
  1625. HasIncrLightRadius := A_Index
  1626. Continue
  1627. }
  1628. IfInString, A_LoopField, increased Quantity
  1629. {
  1630. HasIIQ := A_Index
  1631. Continue
  1632. }
  1633. IfInString, A_LoopField, increased Physical Damage
  1634. {
  1635. HasIncrPhysDmg := A_Index
  1636. Continue
  1637. }
  1638. IfInString, A_LoopField, increased Accuracy Rating
  1639. {
  1640. HasIncrAccuracyRating := A_Index
  1641. Continue
  1642. }
  1643. IfInString, A_LoopField, to Accuracy Rating
  1644. {
  1645. HasToAccuracyRating := A_Index
  1646. Continue
  1647. }
  1648. IfInString, A_LoopField, increased Armour and Evasion
  1649. {
  1650. HasHybridDefences := A_Index
  1651. HasIncrArmourAndEvasion := A_Index
  1652. Continue
  1653. }
  1654. IfInString, A_LoopField, increased Armour and Energy Shield
  1655. {
  1656. HasHybridDefences := A_Index
  1657. HasIncrArmourAndES := A_Index
  1658. Continue
  1659. }
  1660. IfInString, A_LoopField, increased Evasion and Energy Shield
  1661. {
  1662. HasHybridDefences := A_Index
  1663. HasIncrEvasionAndES := A_Index
  1664. Continue
  1665. }
  1666. IfInString, A_LoopField, increased Armour
  1667. {
  1668. HasIncrArmour := A_Index
  1669. Continue
  1670. }
  1671. IfInString, A_LoopField, increased Evasion Rating
  1672. {
  1673. HasIncrEvasion := A_Index
  1674. Continue
  1675. }
  1676. IfInString, A_LoopField, increased Energy Shield
  1677. {
  1678. HasIncrEnergyShield := A_Index
  1679. Continue
  1680. }
  1681. IfInString, A_LoopField, increased Block and Stun Recovery
  1682. {
  1683. HasStunRecovery := A_Index
  1684. Continue
  1685. }
  1686. IfInString, A_LoopField, increased Spell Damage
  1687. {
  1688. HasSpellDamage := A_Index
  1689. Continue
  1690. }
  1691. IfInString, A_LoopField, to maximum Mana
  1692. {
  1693. HasMaxMana := A_Index
  1694. Continue
  1695. }
  1696. }
  1697.  
  1698. ; Reset the AffixLines "array" and other vars
  1699. ResetAffixDetailVars()
  1700.  
  1701. ; --- SIMPLE AFFIXES ---
  1702.  
  1703. Loop, Parse, ItemDataChunk, `n, `r
  1704. {
  1705. If StrLen(A_LoopField) = 0
  1706. {
  1707. Break ; not interested in blank lines
  1708. }
  1709. IfInString, ItemDataChunk, Unidentified
  1710. {
  1711. Break ; not interested in unidentified items
  1712. }
  1713.  
  1714. MarkedAsGuess := False
  1715.  
  1716. ; msgbox, % ItemDataChunk
  1717.  
  1718. ; Note: yes, this superlong IfInString structure sucks
  1719. ; but hey, AHK sucks as a scripting language, so bite me.
  1720. ; But in all seriousness, the incrementing parts could be
  1721. ; covered with one label+goto per affix type but I decided
  1722. ; not to because the if bodies are actually placeholders
  1723. ; for a system that looks up max and min values possible
  1724. ; per affix from a collection of text files. The latter is
  1725. ; a TODO for a future version of the script though.
  1726.  
  1727. ; Global CurrValue ; d
  1728. CurrValue := GetActualValue(A_LoopField)
  1729. CurrTier := 0
  1730. BracketLevel := 0
  1731.  
  1732. ;msgbox, CurrTier: %CurrTier%
  1733.  
  1734. ; Suffixes
  1735.  
  1736. IfInString, A_LoopField, increased Attack Speed
  1737. {
  1738. NumSuffixes += 1
  1739. If (ItemBaseType == "Weapon") ; ItemBaseType is Global!
  1740. {
  1741. ValueRange := LookupAffixData("data\AttackSpeed_Weapons.txt", ItemLevel, CurrValue, "", CurrTier)
  1742. }
  1743. Else
  1744. {
  1745. ValueRange := LookupAffixData("data\AttackSpeed_ArmourAndItems.txt", ItemLevel, CurrValue, "", CurrTier)
  1746. }
  1747. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1748. Continue
  1749. }
  1750. IfInString, A_LoopField, increased Accuracy Rating
  1751. {
  1752. AffixType := "Comp. Suffix"
  1753. ValueRange := LookupAffixData("data\IncrAccuracyRating_LightRadius.txt", ItemLevel, CurrValue, "", CurrTier)
  1754. NumSuffixes += 1
  1755. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  1756. Continue
  1757. }
  1758.  
  1759. IfInString, A_LoopField, to all Attributes
  1760. {
  1761. NumSuffixes += 1
  1762. ValueRange := LookupAffixData("data\ToAllAttributes.txt", ItemLevel, CurrValue, "", CurrTier)
  1763. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1764. Continue
  1765. }
  1766. IfInString, A_LoopField, to Strength
  1767. {
  1768. NumSuffixes += 1
  1769. ValueRange := LookupAffixData("data\ToStrength.txt", ItemLevel, CurrValue, "", CurrTier)
  1770. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1771. Continue
  1772. }
  1773. IfInString, A_LoopField, to Intelligence
  1774. {
  1775. NumSuffixes += 1
  1776. ValueRange := LookupAffixData("data\ToIntelligence.txt", ItemLevel, CurrValue, "", CurrTier)
  1777. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1778. Continue
  1779. }
  1780. IfInString, A_LoopField, to Dexterity
  1781. {
  1782. NumSuffixes += 1
  1783. ValueRange := LookupAffixData("data\ToDexterity.txt", ItemLevel, CurrValue, "", CurrTier)
  1784. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1785. Continue
  1786. }
  1787. IfInString, A_LoopField, increased Cast Speed
  1788. {
  1789. NumSuffixes += 1
  1790. ValueRange := LookupAffixData("data\CastSpeed.txt", ItemLevel, CurrValue, "", CurrTier)
  1791. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1792. Continue
  1793. }
  1794. ; This needs to come before "Critical Strike Chance" !
  1795. IfInString, A_LoopField, increased Critical Strike Chance for Spells
  1796. {
  1797. NumSuffixes += 1
  1798. ValueRange := LookupAffixData("data\SpellCritChance.txt", ItemLevel, CurrValue, "", CurrTier)
  1799. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1800. Continue
  1801. }
  1802. IfInString, A_LoopField, Critical Strike Chance
  1803. {
  1804. If (ItemSubType == "Quiver" or ItemSubType == "Amulet")
  1805. {
  1806. ValueRange := LookupAffixData("data\CritChance_AmuletsAndQuivers.txt", ItemLevel, CurrValue, "", CurrTier)
  1807. }
  1808. Else
  1809. {
  1810. ValueRange := LookupAffixData("data\CritChance_Weapons.txt", ItemLevel, CurrValue, "", CurrTier)
  1811. }
  1812. NumSuffixes += 1
  1813. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1814. Continue
  1815. }
  1816. IfInString, A_LoopField, Critical Strike Multiplier
  1817. {
  1818. If (ItemSubType == "Quiver" or ItemSubType == "Amulet")
  1819. {
  1820. ValueRange := LookupAffixData("data\CritMultiplier_AmuletsAndQuivers.txt", ItemLevel, CurrValue, "", CurrTier)
  1821. }
  1822. Else
  1823. {
  1824. ValueRange := LookupAffixData("data\CritMultiplier_Weapons.txt", ItemLevel, CurrValue, "", CurrTier)
  1825. }
  1826. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1827. NumSuffixes += 1
  1828. Continue
  1829. }
  1830. IfInString, A_LoopField, increased Fire Damage
  1831. {
  1832. NumSuffixes += 1
  1833. ValueRange := LookupAffixData("data\IncrFireDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  1834. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1835. Continue
  1836. }
  1837. IfInString, A_LoopField, increased Cold Damage
  1838. {
  1839. NumSuffixes += 1
  1840. ValueRange := LookupAffixData("data\IncrColdDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  1841. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1842. Continue
  1843. }
  1844. IfInString, A_LoopField, increased Lightning Damage
  1845. {
  1846. NumSuffixes += 1
  1847. ValueRange := LookupAffixData("data\IncrLightningDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  1848. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1849. Continue
  1850. }
  1851. IfInString, A_LoopField, increased Light Radius
  1852. {
  1853. ValueRange := LookupAffixData("data\LightRadius_AccuracyRating.txt", ItemLevel, CurrValue, "", CurrTier)
  1854. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Comp. Suffix", ValueRange, CurrTier), A_Index)
  1855. Continue
  1856. }
  1857. IfInString, A_LoopField, Block Chance
  1858. {
  1859. NumSuffixes += 1
  1860. ValueRange := LookupAffixData("data\BlockChance.txt", ItemLevel, CurrValue, "", CurrTier)
  1861. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1862. Continue
  1863. }
  1864.  
  1865. ; Flask effects (on belts)
  1866. IfInString, A_LoopField, reduced Flask Charges used
  1867. {
  1868. NumSuffixes += 1
  1869. ValueRange := LookupAffixData("data\FlaskChargesUsed.txt", ItemLevel, CurrValue, "", CurrTier)
  1870. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1871. Continue
  1872. }
  1873. IfInString, A_LoopField, increased Flask Charges gained
  1874. {
  1875. NumSuffixes += 1
  1876. ValueRange := LookupAffixData("data\FlaskChargesGained.txt", ItemLevel, CurrValue, "", CurrTier)
  1877. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1878. Continue
  1879. }
  1880. IfInString, A_LoopField, increased Flask effect duration
  1881. {
  1882. NumSuffixes += 1
  1883. ValueRange := LookupAffixData("data\FlaskDuration.txt", ItemLevel, CurrValue, "", CurrTier)
  1884. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1885. Continue
  1886. }
  1887.  
  1888. ; Flasks Suffixes
  1889. ; only applicable to *drumroll* ... flasks
  1890. IfInString, A_LoopField, Dispels
  1891. {
  1892. ; covers Shock, Burning and Frozen and Chilled
  1893. If (NumSuffixes < 1)
  1894. {
  1895. NumSuffixes += 1
  1896. }
  1897. Continue
  1898. }
  1899. IfInString, A_LoopField, Removes Bleeding
  1900. {
  1901. If (NumSuffixes < 1)
  1902. {
  1903. NumSuffixes += 1
  1904. }
  1905. Continue
  1906. }
  1907. IfInString, A_LoopField, Removes Curses on use
  1908. {
  1909. If (NumSuffixes < 1)
  1910. {
  1911. NumSuffixes += 1
  1912. }
  1913. Continue
  1914. }
  1915. IfInString, A_LoopField, during flask effect
  1916. {
  1917. If (NumSuffixes < 1)
  1918. {
  1919. NumSuffixes += 1
  1920. }
  1921. Continue
  1922. }
  1923. IfInString, A_LoopField, Adds Knockback
  1924. {
  1925. If (NumSuffixes < 1)
  1926. {
  1927. NumSuffixes += 1
  1928. }
  1929. Continue
  1930. }
  1931. IfInString, A_LoopField, Life Recovery to Minions
  1932. {
  1933. If (NumSuffixes < 1)
  1934. {
  1935. NumSuffixes += 1
  1936. }
  1937. Continue
  1938. }
  1939. ; END Flask Suffixes
  1940.  
  1941. IfInString, A_LoopField, increased Quantity
  1942. {
  1943. NumSuffixes += 1
  1944. ValueRange := LookupAffixData("data\IIQ.txt", ItemLevel, CurrValue, "", CurrTier)
  1945. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1946. Continue
  1947. }
  1948. IfInString, A_LoopField, Life gained on Kill
  1949. {
  1950. NumSuffixes += 1
  1951. ValueRange := LookupAffixData("data\LifeOnKill.txt", ItemLevel, CurrValue, "", CurrTier)
  1952. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1953. Continue
  1954. }
  1955. IfInString, A_LoopField, Life gained for each enemy hit by your Attacks
  1956. {
  1957. NumSuffixes += 1
  1958. ValueRange := LookupAffixData("data\LifeOnHit.txt", ItemLevel, CurrValue, "", CurrTier)
  1959. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1960. Continue
  1961. }
  1962. IfInString, A_LoopField, Life Regenerated per second
  1963. {
  1964. NumSuffixes += 1
  1965. ValueRange := LookupAffixData("data\LifeRegen.txt", ItemLevel, CurrValue, "", CurrTier)
  1966. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1967. Continue
  1968. }
  1969. IfInString, A_LoopField, Mana Gained on Kill
  1970. {
  1971. ; Not a typo: 'G' in Gained is capital here as opposed to 'Life gained'
  1972. NumSuffixes += 1
  1973. ValueRange := LookupAffixData("data\ManaOnKill.txt", ItemLevel, CurrValue, "", CurrTier)
  1974. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1975. Continue
  1976. }
  1977. IfInString, A_LoopField, increased Mana Regeneration Rate
  1978. {
  1979. NumSuffixes += 1
  1980. ValueRange := LookupAffixData("data\ManaRegen.txt", ItemLevel, CurrValue, "", CurrTier)
  1981. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1982. Continue
  1983. }
  1984. IfInString, A_LoopField, increased Projectile Speed
  1985. {
  1986. NumSuffixes += 1
  1987. ValueRange := LookupAffixData("data\ProjectileSpeed.txt", ItemLevel, CurrValue, "", CurrTier)
  1988. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1989. Continue
  1990. }
  1991. IfInString, A_LoopField, reduced Attribute Requirements
  1992. {
  1993. NumSuffixes += 1
  1994. ValueRange := LookupAffixData("data\ReducedAttrReqs.txt", ItemLevel, CurrValue, "", CurrTier)
  1995. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1996. Continue
  1997. }
  1998. IfInString, A_LoopField, to all Elemental Resistances
  1999. {
  2000. NumSuffixes += 1
  2001. ValueRange := LookupAffixData("data\AllResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2002. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2003. Continue
  2004. }
  2005. IfInString, A_LoopField, to Fire Resistance
  2006. {
  2007. NumSuffixes += 1
  2008. ValueRange := LookupAffixData("data\FireResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2009. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2010. Continue
  2011. }
  2012. IfInString, A_LoopField, to Lightning Resistance
  2013. {
  2014. NumSuffixes += 1
  2015. ValueRange := LookupAffixData("data\LightningResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2016. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2017. Continue
  2018. }
  2019. IfInString, A_LoopField, to Cold Resistance
  2020. {
  2021. NumSuffixes += 1
  2022. ValueRange := LookupAffixData("data\ColdResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2023. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2024. Continue
  2025. }
  2026. IfInString, A_LoopField, to Chaos Resistance
  2027. {
  2028. NumSuffixes += 1
  2029. ValueRange := LookupAffixData("data\ChaosResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2030. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2031. Continue
  2032. }
  2033. If RegExMatch(A_LoopField, ".*to (Cold|Fire|Lightning) and (Cold|Fire|Lightning) Resistances")
  2034. {
  2035. ; Catches two-stone rings and the like which have "+#% to Cold and Lightning Resistances"
  2036. IfInString, A_LoopField, Fire
  2037. {
  2038. NumSuffixes += 1
  2039. ValueRange := LookupAffixData("data\FireResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2040. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2041. Continue
  2042. }
  2043. IfInString, A_LoopField, Lightning
  2044. {
  2045. NumSuffixes += 1
  2046. ValueRange := LookupAffixData("data\LightningResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2047. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2048. Continue
  2049. }
  2050. IfInString, A_LoopField, Cold
  2051. {
  2052. NumSuffixes += 1
  2053. ValueRange := LookupAffixData("data\ColdResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2054. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2055. Continue
  2056. }
  2057. }
  2058. IfInString, A_LoopField, increased Stun Duration on enemies
  2059. {
  2060. NumSuffixes += 1
  2061. ValueRange := LookupAffixData("data\StunDuration.txt", ItemLevel, CurrValue, "", CurrTier)
  2062. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2063. Continue
  2064. }
  2065. IfInString, A_LoopField, reduced Enemy Stun Threshold
  2066. {
  2067. NumSuffixes += 1
  2068. ValueRange := LookupAffixData("data\StunThreshold.txt", ItemLevel, CurrValue, "", CurrTier)
  2069. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2070. Continue
  2071. }
  2072.  
  2073. ; Prefixes
  2074.  
  2075. IfInString, A_LoopField, to Armour
  2076. {
  2077. NumPrefixes += 1
  2078. If (ItemBaseType == "Item")
  2079. {
  2080. ; Global
  2081. ValueRange := LookupAffixData("data\ToArmour_Items.txt", ItemLevel, CurrValue, "", CurrTier)
  2082. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2083. }
  2084. Else
  2085. {
  2086. ; Local
  2087. ValueRange := LookupAffixData("data\ToArmour_WeaponsAndArmour.txt", ItemLevel, CurrValue, "", CurrTier)
  2088. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2089. }
  2090. Continue
  2091. }
  2092. IfInString, A_LoopField, increased Armour and Evasion
  2093. {
  2094. AffixType := "Prefix"
  2095. AEBracketLevel := 0
  2096. ValueRange := LookupAffixData("data\ArmourAndEvasion.txt", ItemLevel, CurrValue, AEBracketLevel, CurrTier)
  2097. If (HasStunRecovery)
  2098. {
  2099. AEBracketLevel2 := AEBracketLevel
  2100.  
  2101. AEBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, AEBracketLevel2)
  2102. If (Not IsValidRange(ValueRange) AND IsValidBracket(AEBracket))
  2103. {
  2104. ValueRange := LookupAffixData("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, AEBracketLevel2, CurrTier)
  2105. }
  2106. AffixType := "Comp. Prefix"
  2107. BSRecBracketLevel := 0
  2108. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2109. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", AEBracketLevel2, "", BSRecBracketLevel)
  2110. If (Not IsValidRange(ValueRange))
  2111. {
  2112. ValueRange := LookupAffixData(PrefixPathOther, ItemLevel, CurrValue, AEBracketLevel, CurrTier)
  2113. }
  2114. If (Not IsValidBracket(BSRecPartial))
  2115. {
  2116. ; This means that we are actually dealing with a Prefix + Comp. Prefix.
  2117. ; To get the part for the hybrid defence that is contributed by the straight prefix,
  2118. ; lookup the bracket level for the B&S Recovery line and then work out the partials
  2119. ; for the hybrid stat from the bracket level of B&S.
  2120. ; Example:
  2121. ; 87% increased Armour and Evasion
  2122. ; 7% increased Block and Stun Recovery
  2123. ;
  2124. ; 1) 7% B&S indicates bracket level 2 (6-7)
  2125. ; 2) lookup bracket level 2 from the hybrid stat + block and stun recovery table
  2126. ; This works out to be 6-14.
  2127. ; 3) subtract 6-14 from 87 to get the rest contributed by the hybrid stat as pure prefix.
  2128. ; Currently when subtracting a range from a single value we just use the range's
  2129. ; max as single value. This may need changing depending on circumstance but it
  2130. ; works for now. EDIT: no longer the case, now uses RangeMid(...). #'s below changed to
  2131. ; reflect that...
  2132. ; 87-10 = 77
  2133. ; 4) lookup affix data for increased Armour and Evasion with value of 77
  2134. ; We now know, this is a Comp. Prefix+Prefix
  2135. BSRecBracketLevel := 0
  2136. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2137. If (Not IsValidBracket(BSRecPartial))
  2138. {
  2139. ; This means that the hybrid stat is a Comp. Prefix+Prefix and BS rec is a Comp. Prefix+Suffix
  2140. ; This is ambiguous and tough to resolve, but we'll try anyway...
  2141. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, "", BSRecBracketLevel)
  2142. }
  2143. ; msgbox, BSRecValue: %BSRecValue%`, BSRecBracketLevel: %BSRecBracketLevel%`, BSRecPartial: %BSRecPartial%
  2144.  
  2145. AEBSBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", BSRecBracketLevel)
  2146.  
  2147. ; msgbox, AEBSBracket: %AEBSBracket%
  2148. If (Not WithinBounds(AEBSBracket, CurrValue))
  2149. {
  2150. AERest := CurrValue - RangeMid(AEBSBracket)
  2151. AEBracket := LookupAffixBracket("data\ArmourAndEvasion.txt", ItemLevel, AERest)
  2152. ; msgbox, AEBracket: %AEBracket%`, AEBSBracket: %AEBSBracket%`,AERest: %AERest%
  2153.  
  2154. If (Not IsValidBracket(AEBracket))
  2155. {
  2156. AEBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue)
  2157. }
  2158. If (Not WithinBounds(AEBracket, CurrValue))
  2159. {
  2160. ValueRange := AddRange(AEBSBracket, AEBracket)
  2161. ValueRange := MarkAsGuesstimate(ValueRange)
  2162. AffixType := "Comp. Prefix+Prefix"
  2163. NumPrefixes += 1
  2164. }
  2165. }
  2166.  
  2167. If (WithinBounds(BSRecPartial, BSRecValue))
  2168. {
  2169. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2170. BSRecPartial =
  2171. }
  2172. }
  2173. }
  2174. NumPrefixes += 1
  2175. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2176. Continue
  2177. }
  2178. IfInString, A_LoopField, increased Armour and Energy Shield
  2179. {
  2180. AffixType := "Prefix"
  2181. AESBracketLevel := 0
  2182. ValueRange := LookupAffixData("data\ArmourAndEnergyShield.txt", ItemLevel, CurrValue, AESBracketLevel, CurrTier)
  2183. If (HasStunRecovery)
  2184. {
  2185. AESBracketLevel2 := AESBracketLevel
  2186.  
  2187. AESBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, AESBracketLevel2)
  2188. If (Not IsValidRange(ValueRange) AND IsValidBracket(AESBracket))
  2189. {
  2190. ValueRange := LookupAffixData("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, AESBracketLevel2, CurrTier)
  2191. }
  2192. AffixType := "Comp. Prefix"
  2193. BSRecBracketLevel := 0
  2194. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2195. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", AESBracketLevel2, "", BSRecBracketLevel)
  2196. If (Not IsValidBracket(BSRecPartial))
  2197. {
  2198. BSRecPartial := LookupAffixBracket("data\StunRecovery_Armour.txt", AESBracketLevel, "", BSRecBracketLevel)
  2199. }
  2200. If (Not IsValidBracket(BSRecPartial))
  2201. {
  2202. BSRecBracketLevel := 0
  2203. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2204. If (Not IsValidBracket(BSRecPartial))
  2205. {
  2206. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, "", BSRecBracketLevel)
  2207. }
  2208.  
  2209. AESBSBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", BSRecBracketLevel)
  2210.  
  2211. If (Not WithinBounds(AESBSBracket, CurrValue))
  2212. {
  2213. AESRest := CurrValue - RangeMid(AESBSBracket)
  2214. AESBracket := LookupAffixBracket("data\ArmourAndEnergyShield.txt", ItemLevel, AESRest)
  2215.  
  2216. If (Not IsValidBracket(AESBracket))
  2217. {
  2218. AESBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue)
  2219. }
  2220. If (Not WithinBounds(AESBracket, CurrValue))
  2221. {
  2222. ValueRange := AddRange(AESBSBracket, AESBracket)
  2223. ValueRange := MarkAsGuesstimate(ValueRange)
  2224. AffixType := "Comp. Prefix+Prefix"
  2225. NumPrefixes += 1
  2226. }
  2227. }
  2228. If (WithinBounds(BSRecPartial, BSRecValue))
  2229. {
  2230. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2231. BSRecPartial =
  2232. }
  2233. }
  2234. }
  2235. NumPrefixes += 1
  2236. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2237. Continue
  2238. }
  2239. IfInString, A_LoopField, increased Evasion and Energy Shield
  2240. {
  2241. AffixType := "Prefix"
  2242. EESBracketLevel := 0
  2243. ValueRange := LookupAffixData("data\EvasionAndEnergyShield.txt", ItemLevel, CurrValue, EESBracketLevel, CurrTier)
  2244. If (HasStunRecovery)
  2245. {
  2246. EESBracketLevel2 := EESBracketLevel
  2247.  
  2248. EESBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, EESBracketLevel2)
  2249. If (Not IsValidRange(ValueRange) AND IsValidBracket(EESBracket))
  2250. {
  2251. ValueRange := LookupAffixData("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, EESBracketLevel2, CurrTier)
  2252. }
  2253.  
  2254. AffixType := "Comp. Prefix"
  2255. BSRecBracketLevel := 0
  2256. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2257. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", EESBracketLevel2, "", BSRecBracketLevel)
  2258. If (Not IsValidBracket(BSRecPartial))
  2259. {
  2260. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", EESBracketLevel, "", BSRecBracketLevel)
  2261. }
  2262. If (Not IsValidBracket(BSRecPartial))
  2263. {
  2264. BSRecBracketLevel := 0
  2265. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2266. If (Not IsValidBracket(BSRecPartial))
  2267. {
  2268. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, "", BSRecBracketLevel)
  2269. }
  2270.  
  2271. EESBSBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", BSRecBracketLevel)
  2272.  
  2273. If (Not WithinBounds(EESBSBracket, CurrValue))
  2274. {
  2275. EESRest := CurrValue - RangeMid(EESBSBracket)
  2276. EESBracket := LookupAffixBracket("data\EvasionAndEnergyShield.txt", ItemLevel, EESRest)
  2277.  
  2278. If (Not IsValidBracket(EESBracket))
  2279. {
  2280. EESBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue)
  2281. }
  2282. If (Not WithinBounds(EESBracket, CurrValue))
  2283. {
  2284. ValueRange := AddRange(EESBSBracket, EESBracket)
  2285. ValueRange := MarkAsGuesstimate(ValueRange)
  2286. AffixType := "Comp. Prefix+Prefix"
  2287. NumPrefixes += 1
  2288. }
  2289. }
  2290.  
  2291. If (WithinBounds(BSRecPartial, BSRecValue))
  2292. {
  2293. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2294. BSRecPartial =
  2295. }
  2296. }
  2297. }
  2298. NumPrefixes += 1
  2299. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2300. Continue
  2301. }
  2302. IfInString, A_LoopField, increased Armour
  2303. {
  2304. AffixType := "Prefix"
  2305. IABracketLevel := 0
  2306. If (ItemBaseType == "Item")
  2307. {
  2308. ; Global
  2309. PrefixPath := "data\IncrArmour_Items.txt"
  2310. PrefixPathOther := "data\IncrArmour_WeaponsAndArmour.txt"
  2311. }
  2312. Else
  2313. {
  2314. ; Local
  2315. PrefixPath := "data\IncrArmour_WeaponsAndArmour.txt"
  2316. PrefixPathOther := "data\IncrArmour_Items.txt"
  2317. }
  2318. ValueRange := LookupAffixData(PrefixPath, ItemLevel, CurrValue, IABracketLevel, CurrTier)
  2319. If (Not IsValidRange(ValueRange))
  2320. {
  2321. ValueRange := LookupAffixData(PrefixPathOther, ItemLevel, CurrValue, IABracketLevel, CurrTier)
  2322. }
  2323. If (HasStunRecovery)
  2324. {
  2325. IABracketLevel2 := IABracketLevel
  2326.  
  2327. ASRBracket := LookupAffixBracket("data\Armour_StunRecovery.txt", ItemLevel, CurrValue, IABracketLevel2)
  2328. If (Not IsValidRange(ValueRange) AND IsValidBracket(ASRBracket))
  2329. {
  2330. ValueRange := LookupAffixData("data\Armour_StunRecovery.txt", ItemLevel, CurrValue, IABracketLevel2, CurrTier)
  2331. }
  2332.  
  2333. AffixType := "Comp. Prefix"
  2334. BSRecBracketLevel := 0
  2335. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2336. BSRecPartial := LookupAffixBracket("data\StunRecovery_Armour.txt", IABracketLevel2, "", BSRecBracketLevel)
  2337. ;msgbox, IABracketLevel: %IABracketLevel%`, BSRecValue: %BSRecValue%`, BSRecBracketLevel: %BSRecBracketLevel%`, BSRecPartial: %BSRecPartial%
  2338. If (Not IsValidBracket(BSRecPartial))
  2339. {
  2340. BSRecPartial := LookupAffixBracket("data\StunRecovery_Armour.txt", IABracketLevel, "", BSRecBracketLevel)
  2341. }
  2342. If (Not IsValidBracket(BSRecPartial))
  2343. {
  2344. BSRecBracketLevel := 0
  2345. BSRecPartial := LookupAffixBracket("data\StunRecovery_Armour.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2346. If (Not IsValidBracket(BSRecPartial))
  2347. {
  2348. BSRecPartial := LookupAffixBracket("data\StunRecovery_Armour.txt", ItemLevel, "", BSRecBracketLevel)
  2349. }
  2350. ;msgbox, BSRecValue: %BSRecValue%`, BSRecBracketLevel: %BSRecBracketLevel%`, BSRecPartial: %BSRecPartial%
  2351.  
  2352. IABSBracket := LookupAffixBracket("data\Armour_StunRecovery.txt", BSRecBracketLevel)
  2353.  
  2354. If (Not WithinBounds(IABSBracket, CurrValue))
  2355. {
  2356. IARest := CurrValue - RangeMid(IABSBracket)
  2357. IABracket := LookupAffixBracket(PrefixPath, ItemLevel, IARest)
  2358. ;msgbox, IABracket: %IABracket%`, IABSBracket: %IABSBracket%`, IARest: %IARest%
  2359. If (Not IsValidBracket(IABracket))
  2360. {
  2361. IABracket := LookupAffixBracket(PrefixPath, ItemLevel, CurrValue)
  2362. }
  2363. If (Not WithinBounds(IABracket, CurrValue))
  2364. {
  2365. ValueRange := AddRange(IABSBracket, IABracket)
  2366. ValueRange := MarkAsGuesstimate(ValueRange)
  2367. AffixType := "Comp. Prefix+Prefix"
  2368. NumPrefixes += 1
  2369. }
  2370. }
  2371.  
  2372. If (WithinBounds(BSRecPartial, BSRecValue))
  2373. {
  2374. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2375. BSRecPartial =
  2376. }
  2377. }
  2378. }
  2379. NumPrefixes += 1
  2380. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2381. Continue
  2382. }
  2383. IfInString, A_LoopField, to Evasion Rating
  2384. {
  2385. NumPrefixes += 1
  2386. If (ItemBaseType == "Item")
  2387. {
  2388. ValueRange := LookupAffixData("data\ToEvasion_Items.txt", ItemLevel, CurrValue, "", CurrTier)
  2389. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2390. }
  2391. Else
  2392. {
  2393. ValueRange := LookupAffixData("data\ToEvasion_Armour.txt", ItemLevel, CurrValue, "", CurrTier)
  2394. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2395. }
  2396. Continue
  2397. }
  2398. IfInString, A_LoopField, increased Evasion Rating
  2399. {
  2400. AffixType := "Prefix"
  2401. IEBracketLevel := 0
  2402. If (ItemBaseType == "Item")
  2403. {
  2404. ; Global
  2405. PrefixPath := "data\IncrEvasion_Items.txt"
  2406. PrefixPathOther := "data\IncrEvasion_Armour.txt"
  2407. }
  2408. Else
  2409. {
  2410. ; Local
  2411. PrefixPath := "data\IncrEvasion_Armour.txt"
  2412. PrefixPathOther := "data\IncrEvasion_Items.txt"
  2413. }
  2414. ValueRange := LookupAffixData(PrefixPath, ItemLevel, CurrValue, IEBracketLevel, CurrTier)
  2415. If (Not IsValidRange(ValueRange))
  2416. {
  2417. ValueRange := LookupAffixData(PrefixPathOther, ItemLevel, CurrValue, IEBracketLevel, CurrTier)
  2418. }
  2419. If (HasStunRecovery)
  2420. {
  2421. IEBracketLevel2 := IEBracketLevel
  2422.  
  2423. ; determine composite bracket level and store in IEBracketLevel2, for example:
  2424. ; 8% increased Evasion, 26% increased Block and Stun Recover =>
  2425. ; 8% is bracket level 2 (6-14), so 'B+S Rec from Evasion' level 2 makes BSRec partial 6-7
  2426. ERSRBracket := LookupAffixBracket("data\Evasion_StunRecovery.txt", ItemLevel, CurrValue, IEBracketLevel2)
  2427. If (Not IsValidRange(ValueRange) AND IsValidBracket(ERSRBracket))
  2428. {
  2429. ValueRange := LookupAffixData("data\Evasion_StunRecovery.txt", ItemLevel, CurrValue, IEBracketLevel2, CurrTier)
  2430. }
  2431.  
  2432. AffixType := "Comp. Prefix"
  2433. BSRecBracketLevel := 0
  2434. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2435. BSRecPartial := LookupAffixBracket("data\StunRecovery_Evasion.txt", IEBracketLevel2, "", BSRecBracketLevel)
  2436. ;msgbox, IEBracketLevel: %IEBracketLevel%`, ValueRange: %ValueRange%, BSRecPartial: %BSRecPartial%, BSRecValue: %BSRecValue%, IEBracketLevel: %IEBracketLevel%
  2437. If (Not IsValidBracket(BSRecPartial))
  2438. {
  2439. BSRecPartial := LookupAffixBracket("data\StunRecovery_Evasion.txt", IEBracketLevel, "", BSRecBracketLevel)
  2440. }
  2441. If (Not IsValidRange(ValueRange) and (Not IsValidBracket(BSRecPartial) or Not WithinBounds(BSRecPartial, BSRecValue)))
  2442. {
  2443. BSRecBracketLevel := 0
  2444. BSRecPartial := LookupAffixBracket("data\StunRecovery_Evasion.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2445. If (Not IsValidBracket(BSRecPartial))
  2446. {
  2447. BSRecPartial := LookupAffixBracket("data\StunRecovery_Evasion.txt", ItemLevel, "", BSRecBracketLevel)
  2448. }
  2449.  
  2450. IEBSBracket := LookupAffixBracket("data\Evasion_StunRecovery.txt", BSRecBracketLevel)
  2451.  
  2452. If (Not WithinBounds(IEBSBracket, CurrValue))
  2453. {
  2454. IERest := CurrValue - RangeMid(IEBSBracket)
  2455. IEBracket := LookupAffixBracket(PrefixPath, ItemLevel, IERest)
  2456. If (Not IsValidBracket(IEBracket))
  2457. {
  2458. IEBracket := LookupAffixBracket(PrefixPath, ItemLevel, CurrValue, "")
  2459. }
  2460. If (Not WithinBounds(IEBracket, CurrValue))
  2461. {
  2462. ; msgbox, IEBracket: %IEBracket%, IEBSBracket: %IEBSBracket%
  2463. ValueRange := AddRange(IEBSBracket, IEBracket)
  2464. ValueRange := MarkAsGuesstimate(ValueRange)
  2465. AffixType := "Comp. Prefix+Prefix"
  2466. NumPrefixes += 1
  2467. }
  2468. }
  2469.  
  2470. If (WithinBounds(BSRecPartial, BSRecValue))
  2471. {
  2472. ; msgbox, BSRecPartial: %BSRecPartial%, BSRecValue: %BSRecValue%
  2473. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2474. BSRecPartial =
  2475. }
  2476. }
  2477. }
  2478. NumPrefixes += 1
  2479. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2480. Continue
  2481. }
  2482. IfInString, A_LoopField, to maximum Energy Shield
  2483. {
  2484. PrefixType := "Prefix"
  2485. If (ItemSubType == "Ring" or ItemSubType == "Amulet" or ItemSubType == "Belt")
  2486. {
  2487. ValueRange := LookupAffixData("data\ToMaxEnergyShield.txt", ItemLevel, CurrValue, "", CurrTier)
  2488. }
  2489. Else
  2490. {
  2491. ValueRange := LookupAffixData("data\ToEnergyShield.txt", ItemLevel, CurrValue, "", CurrTier)
  2492.  
  2493. }
  2494. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2495. NumPrefixes += 1
  2496. Continue
  2497. }
  2498. IfInString, A_LoopField, increased Energy Shield
  2499. {
  2500. AffixType := "Prefix"
  2501. IESBracketLevel := 0
  2502. PrefixPath := "data\IncrEnergyShield.txt"
  2503. ValueRange := LookupAffixData(PrefixPath, ItemLevel, CurrValue, IESBracketLevel, CurrTier)
  2504.  
  2505. If (HasStunRecovery)
  2506. {
  2507. IESBracketLevel2 := IESBracketLevel
  2508.  
  2509. ESSRBracket := LookupAffixBracket("data\EnergyShield_StunRecovery.txt", ItemLevel, CurrValue, IESBracketLevel2)
  2510. If (Not IsValidRange(ValueRange) AND IsValidBracket(ESSRBracket))
  2511. {
  2512. ValueRange := LookupAffixData("data\EnergyShield_StunRecovery.txt", ItemLevel, CurrValue, IESBracketLevel2, CurrTier)
  2513. }
  2514.  
  2515. AffixType := "Comp. Prefix"
  2516. BSRecBracketLevel := 0
  2517. BSRecPartial := LookupAffixBracket("data\StunRecovery_EnergyShield.txt", IESBracketLevel2, "", BSRecBracketLevel)
  2518. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2519. If (Not IsValidBracket(BSRecPartial))
  2520. {
  2521. BSRecPartial := LookupAffixBracket("data\StunRecovery_EnergyShield.txt", IESBracketLevel, "", BSRecBracketLevel)
  2522. }
  2523. If (Not IsValidBracket(BSRecPartial))
  2524. {
  2525. BSRecBracketLevel := 0
  2526. BSRecPartial := LookupAffixBracket("data\StunRecovery_EnergyShield.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2527. If (Not IsValidBracket(BSRecPartial))
  2528. {
  2529. BSRecPartial := LookupAffixBracket("data\StunRecovery_EnergyShield.txt", ItemLevel, "", BSRecBracketLevel)
  2530. }
  2531. IESBSBracket := LookupAffixBracket("data\EnergyShield_StunRecovery.txt", BSRecBracketLevel)
  2532.  
  2533. If (Not WithinBounds(IEBSBracket, CurrValue))
  2534. {
  2535. IESRest := CurrValue - RangeMid(IESBSBracket)
  2536. IESBracket := LookupAffixBracket(PrefixPath, ItemLevel, IESRest)
  2537.  
  2538. If (Not WithinBounds(IESBracket, CurrValue))
  2539. {
  2540. ValueRange := AddRange(IESBSBracket, IESBracket)
  2541. ValueRange := MarkAsGuesstimate(ValueRange)
  2542. AffixType := "Comp. Prefix+Prefix"
  2543. NumPrefixes += 1
  2544. }
  2545. }
  2546.  
  2547. If (WithinBounds(BSRecPartial, BSRecValue))
  2548. {
  2549. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2550. BSRecPartial =
  2551. }
  2552. }
  2553. }
  2554. NumPrefixes += 1
  2555. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2556. Continue
  2557. }
  2558. IfInString, A_LoopField, increased maximum Energy Shield
  2559. {
  2560. NumPrefixes += 1
  2561. ValueRange := LookupAffixData("data\IncrMaxEnergyShield_Amulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2562. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2563. Continue
  2564. }
  2565. If RegExMatch(A_LoopField, "Adds \d+?\-\d+? Physical Damage")
  2566. {
  2567. If (ItemBaseType == "Weapon")
  2568. {
  2569. If (ItemSubType == "Bow")
  2570. {
  2571. ValueRange := LookupAffixData("data\AddedPhysDamage_2H.txt", ItemLevel, CurrValue, "", CurrTier)
  2572. }
  2573. Else
  2574. {
  2575. If (ItemGripType == "1H") ; one handed weapons
  2576. {
  2577. ValueRange := LookupAffixData("data\AddedPhysDamage_1H.txt", ItemLevel, CurrValue, "", CurrTier)
  2578. }
  2579. Else
  2580. {
  2581. ValueRange := LookupAffixData("data\AddedPhysDamage_2H.txt", ItemLevel, CurrValue, "", CurrTier)
  2582. }
  2583. }
  2584. }
  2585. Else
  2586. {
  2587. If (ItemSubType == "Amulet")
  2588. {
  2589. ValueRange := LookupAffixData("data\AddedPhysDamage_Amulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2590. }
  2591. Else
  2592. {
  2593. If (ItemSubType == "Quiver")
  2594. {
  2595. ValueRange := LookupAffixData("data\AddedPhysDamage_Quivers.txt", ItemLevel, CurrValue, "", CurrTier)
  2596. }
  2597. Else
  2598. {
  2599. If (ItemSubType == "Ring")
  2600. {
  2601. ValueRange := LookupAffixData("data\AddedPhysDamage_Rings.txt", ItemLevel, CurrValue, "", CurrTier)
  2602. }
  2603. Else
  2604. {
  2605. ; there is no Else for rare items, but some uniques have added phys damage
  2606. ; just lookup in 1H for now
  2607. ValueRange := LookupAffixData("data\AddedPhysDamage_Amulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2608. }
  2609. }
  2610. }
  2611. }
  2612. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2613. NumPrefixes += 1
  2614. Continue
  2615. }
  2616. If RegExMatch(A_LoopField, "Adds \d+?\-\d+? Cold Damage")
  2617. {
  2618. If (ItemSubType == "Amulet" or ItemSubType == "Ring")
  2619. {
  2620. ValueRange := LookupAffixData("data\AddedColdDamage_RingsAndAmulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2621. }
  2622. Else
  2623. {
  2624. If (ItemSubType == "Gloves")
  2625. {
  2626. ValueRange := LookupAffixData("data\AddedColdDamage_Gloves.txt", ItemLevel, CurrValue, "", CurrTier)
  2627. }
  2628. Else
  2629. {
  2630. If (ItemSubType == "Quiver")
  2631. {
  2632. ValueRange := LookupAffixData("data\AddedColdDamage_Quivers.txt", ItemLevel, CurrValue, "", CurrTier)
  2633. }
  2634. Else
  2635. {
  2636. If (ItemGripType == "1H")
  2637. {
  2638. ValueRange := LookupAffixData("data\AddedColdDamage_1H.txt", ItemLevel, CurrValue, "", CurrTier)
  2639. }
  2640. Else
  2641. {
  2642. ValueRange := LookupAffixData("data\AddedColdDamage_2H.txt", ItemLevel, CurrValue, "", CurrTier)
  2643. }
  2644. }
  2645. }
  2646. }
  2647. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2648. NumPrefixes += 1
  2649. Continue
  2650. }
  2651. If RegExMatch(A_LoopField, "Adds \d+?\-\d+? Fire Damage")
  2652. {
  2653. If (ItemSubType == "Amulet" or ItemSubType == "Ring")
  2654. {
  2655. ValueRange := LookupAffixData("data\AddedFireDamage_RingsAndAmulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2656. }
  2657. Else
  2658. {
  2659. If (ItemSubType == "Gloves")
  2660. {
  2661. ValueRange := LookupAffixData("data\AddedFireDamage_Gloves.txt", ItemLevel, CurrValue, "", CurrTier)
  2662. }
  2663. Else
  2664. {
  2665. If (ItemSubType == "Quiver")
  2666. {
  2667. ValueRange := LookupAffixData("data\AddedFireDamage_Quivers.txt", ItemLevel, CurrValue, "", CurrTier)
  2668. }
  2669. Else
  2670. {
  2671. If (ItemGripType == "1H") ; one handed weapons
  2672. {
  2673. ValueRange := LookupAffixData("data\AddedFireDamage_1H.txt", ItemLevel, CurrValue, "", CurrTier)
  2674. }
  2675. Else
  2676. {
  2677. ValueRange := LookupAffixData("data\AddedFireDamage_2H.txt", ItemLevel, CurrValue, "", CurrTier)
  2678. }
  2679. }
  2680. }
  2681. }
  2682. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2683. NumPrefixes += 1
  2684. Continue
  2685. }
  2686. If RegExMatch(A_LoopField, "Adds \d+?\-\d+? Lightning Damage")
  2687. {
  2688. If (ItemSubType == "Amulet" or ItemSubType == "Ring")
  2689. {
  2690. ValueRange := LookupAffixData("data\AddedLightningDamage_RingsAndAmulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2691. }
  2692. Else
  2693. {
  2694. If (ItemSubType == "Gloves")
  2695. {
  2696. ValueRange := LookupAffixData("data\AddedLightningDamage_Gloves.txt", ItemLevel, CurrValue, "", CurrTier)
  2697. }
  2698. Else
  2699. {
  2700. If (ItemSubType == "Quiver")
  2701. {
  2702. ValueRange := LookupAffixData("data\AddedLightningDamage_Quivers.txt", ItemLevel, CurrValue, "", CurrTier)
  2703. }
  2704. Else
  2705. {
  2706. If (ItemGripType == "1H") ; one handed weapons
  2707. {
  2708. ValueRange := LookupAffixData("data\AddedLightningDamage_1H.txt", ItemLevel, CurrValue, "", CurrTier)
  2709. }
  2710. Else
  2711. {
  2712. ValueRange := LookupAffixData("data\AddedLightningDamage_2H.txt", ItemLevel, CurrValue, "", CurrTier)
  2713. }
  2714. }
  2715. }
  2716. }
  2717. ActualRange := GetActualValue(A_LoopField)
  2718. AffixType := "Prefix"
  2719. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2720. NumPrefixes += 1
  2721. Continue
  2722. }
  2723. IfInString, A_LoopField, Physical Damage to Melee Attackers
  2724. {
  2725. NumPrefixes += 1
  2726. ValueRange := LookupAffixData("data\PhysDamagereturn.txt", ItemLevel, CurrValue, "", CurrTier)
  2727. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2728. Continue
  2729. }
  2730. IfInString, A_LoopField, Gems in this item
  2731. {
  2732. If (ItemBaseType == "Weapon")
  2733. {
  2734. If (ItemSubType == "Bow")
  2735. {
  2736. ValueRange := LookupAffixData("data\GemLevel_Bow.txt", ItemLevel, CurrValue, "", CurrTier)
  2737. }
  2738. Else
  2739. {
  2740. If (InStr(A_LoopField, "Fire") OR InStr(A_LoopField, "Cold") OR InStr(A_LoopField, "Lightning"))
  2741. {
  2742. ValueRange := LookupAffixData("data\GemLevel_Elemental.txt", ItemLevel, CurrValue, "", CurrTier)
  2743. }
  2744. Else
  2745. {
  2746. If (InStr(A_LoopField, "Melee"))
  2747. {
  2748. ValueRange := LookupAffixData("data\GemLevel_Melee.txt", ItemLevel, CurrValue, "", CurrTier)
  2749. }
  2750. Else
  2751. {
  2752. ; Paragorn's
  2753. ValueRange := LookupAffixData("data\GemLevel.txt", ItemLevel, CurrValue, "", CurrTier)
  2754. }
  2755. }
  2756. }
  2757. }
  2758. Else
  2759. {
  2760. If (InStr(A_LoopField, "Minion"))
  2761. {
  2762. ValueRange := LookupAffixData("data\GemLevel_Minion.txt", ItemLevel, CurrValue, "", CurrTier)
  2763. }
  2764. Else If (InStr(A_LoopField, "Fire") OR InStr(A_LoopField, "Cold") OR InStr(A_LoopField, "Lightning"))
  2765. {
  2766. ValueRange := LookupAffixData("data\GemLevel_Elemental.txt", ItemLevel, CurrValue, "", CurrTier)
  2767. }
  2768. Else If (InStr(A_LoopField, "Melee"))
  2769. {
  2770. ValueRange := LookupAffixData("data\GemLevel_Melee.txt", ItemLevel, CurrValue, "", CurrTier)
  2771. }
  2772. }
  2773. NumPrefixes += 1
  2774. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2775. Continue
  2776. }
  2777. IfInString, A_LoopField, maximum Life
  2778. {
  2779. ValueRange := LookupAffixData("data\MaxLife.txt", ItemLevel, CurrValue, "", CurrTier)
  2780. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2781. NumPrefixes += 1
  2782. Continue
  2783. }
  2784. IfInString, A_LoopField, Physical Attack Damage Leeched as
  2785. {
  2786. NumPrefixes += 1
  2787. ValueRange := LookupAffixData("data\LifeLeech.txt", ItemLevel, CurrValue, "", CurrTier)
  2788. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2789. Continue
  2790. }
  2791. IfInString, A_LoopField, Movement Speed
  2792. {
  2793. NumPrefixes += 1
  2794. ValueRange := LookupAffixData("data\MovementSpeed.txt", ItemLevel, CurrValue, "", CurrTier)
  2795. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2796. Continue
  2797. }
  2798. IfInString, A_LoopField, increased Elemental Damage with Weapons
  2799. {
  2800. NumPrefixes += 1
  2801. ValueRange := LookupAffixData("data\IncrWeaponElementalDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  2802. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2803. Continue
  2804. }
  2805.  
  2806. ; Flask effects (on belts)
  2807. IfInString, A_LoopField, increased Flask Mana Recovery rate
  2808. {
  2809. NumPrefixes += 1
  2810. ValueRange := LookupAffixData("data\FlaskManaRecoveryRate.txt", ItemLevel, CurrValue, "", CurrTier)
  2811. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2812. Continue
  2813. }
  2814. IfInString, A_LoopField, increased Flask Life Recovery rate
  2815. {
  2816. NumPrefixes += 1
  2817. ValueRange := LookupAffixData("data\FlaskLifeRecoveryRate.txt", ItemLevel, CurrValue, "", CurrTier)
  2818. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2819. Continue
  2820. }
  2821.  
  2822. ; Flask prefixes
  2823. IfInString, A_LoopField, Recovery Speed
  2824. {
  2825. If (NumPrefixes < 1)
  2826. {
  2827. NumPrefixes += 1
  2828. }
  2829. Continue
  2830. }
  2831. IfInString, A_LoopField, Amount Recovered
  2832. {
  2833. If (NumPrefixes < 1)
  2834. {
  2835. NumPrefixes += 1
  2836. }
  2837. Continue
  2838. }
  2839. IfInString, A_LoopField, Charges
  2840. {
  2841. If (NumPrefixes < 1)
  2842. {
  2843. NumPrefixes += 1
  2844. }
  2845. Continue
  2846. }
  2847. IfInString, A_LoopField, Instant
  2848. {
  2849. If (NumPrefixes < 1)
  2850. {
  2851. NumPrefixes += 1
  2852. }
  2853. Continue
  2854. }
  2855. IfInString, A_LoopField, Charge when
  2856. {
  2857. If (NumPrefixes < 1)
  2858. {
  2859. NumPrefixes += 1
  2860. }
  2861. Continue
  2862. }
  2863. IfInString, A_LoopField, Recovery when
  2864. {
  2865. If (NumPrefixes < 1)
  2866. {
  2867. NumPrefixes += 1
  2868. }
  2869. Continue
  2870. }
  2871. IfInString, A_LoopField, Mana Recovered
  2872. {
  2873. If (NumPrefixes < 1)
  2874. {
  2875. NumPrefixes += 1
  2876. }
  2877. Continue
  2878. }
  2879. IfInString, A_LoopField, Life Recovered
  2880. {
  2881. If (NumPrefixes < 1)
  2882. {
  2883. NumPrefixes += 1
  2884. }
  2885. Continue
  2886. }
  2887. }
  2888.  
  2889. ; --- COMPLEX AFFIXES ---
  2890.  
  2891. Loop, Parse, ItemDataChunk, `n, `r
  2892. {
  2893. If StrLen(A_LoopField) = 0
  2894. {
  2895. Break ; not interested in blank lines
  2896. }
  2897. IfInString, ItemDataChunk, Unidentified
  2898. {
  2899. Break ; not interested in unidentified items
  2900. }
  2901.  
  2902. CurrValue := GetActualValue(A_LoopField)
  2903.  
  2904. ; "Spell Damage +%" (simple prefix)
  2905. ; "Spell Damage +% (1H)" / "Base Maximum Mana" - Limited to sceptres, wands, and daggers.
  2906. ; "Spell Damage +% (Staff)" / "Base Maximum Mana"
  2907. IfInString, A_LoopField, increased Spell Damage
  2908. {
  2909. AffixType := "Prefix"
  2910. If (HasMaxMana)
  2911. {
  2912. SDBracketLevel := 0
  2913. MMBracketLevel := 0
  2914. MaxManaValue := ExtractValueFromAffixLine(ItemDataChunk, "maximum Mana")
  2915. If (ItemSubType == "Staff")
  2916. {
  2917. SpellDamageBracket := LookupAffixBracket("data\SpellDamage_MaxMana_Staff.txt", ItemLevel, CurrValue, SDBracketLevel)
  2918. If (Not IsValidBracket(SpellDamageBracket))
  2919. {
  2920. AffixType := "Comp. Prefix+Prefix"
  2921. NumPrefixes += 1
  2922.  
  2923. ; need to find the bracket level by looking at max mana value instead
  2924. MaxManaBracket := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", ItemLevel, MaxManaValue, MMBracketLevel)
  2925. If (Not IsValidBracket(MaxManaBracket))
  2926. {
  2927. ; this actually means that both the "increased Spell Damage" line and
  2928. ; the "to maximum Mana" line are made up of composite prefix + prefix
  2929. ; I haven't seen such an item yet but you never know. In any case this
  2930. ; is completely ambiguous and can't be resolved. Mark line with EstInd
  2931. ; so user knows she needs to take a look at it.
  2932. AffixType := "Comp. Prefix+Comp. Prefix"
  2933. ValueRange := StrPad(EstInd, ValueRangeFieldWidth + StrLen(EstInd), "left")
  2934. }
  2935. Else
  2936. {
  2937. SpellDamageBracketFromComp := LookupAffixBracket("data\SpellDamage_MaxMana_Staff.txt", MMBracketLevel)
  2938. SDValueRest := CurrValue - RangeMid(SpellDamageBracketFromComp)
  2939. SpellDamageBracket := LookupAffixBracket("data\SpellDamage_Staff.txt", ItemLevel, SDValueRest, SDBracketLevel)
  2940. ValueRange := AddRange(SpellDamageBracket, SpellDamageBracketFromComp)
  2941. ValueRange := MarkAsGuesstimate(ValueRange)
  2942. }
  2943. }
  2944. Else
  2945. {
  2946. ValueRange := LookupAffixData("data\SpellDamage_MaxMana_Staff.txt", ItemLevel, CurrValue, BracketLevel, CurrTier)
  2947. MaxManaBracket := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", BracketLevel)
  2948. AffixType := "Comp. Prefix"
  2949. }
  2950. }
  2951. Else
  2952. {
  2953. SpellDamageBracket := LookupAffixBracket("data\SpellDamage_MaxMana_1H.txt", ItemLevel, CurrValue, SDBracketLevel)
  2954. If (Not IsValidBracket(SpellDamageBracket))
  2955. {
  2956. AffixType := "Comp. Prefix+Prefix"
  2957. NumPrefixes += 1
  2958.  
  2959. ; need to find the bracket level by looking at max mana value instead
  2960. MaxManaBracket := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", ItemLevel, MaxManaValue, MMBracketLevel)
  2961. If (Not IsValidBracket(MaxManaBracket))
  2962. {
  2963. MaxManaBracket := LookupAffixBracket("data\MaxMana.txt", ItemLevel, MaxManaValue, MMBracketLevel)
  2964. If (IsValidBracket(MaxManaBracket))
  2965. {
  2966. AffixType := "Prefix"
  2967. If (ItemSubType == "Staff")
  2968. {
  2969. ValueRange := LookupAffixData("data\SpellDamage_Staff.txt", ItemLevel, CurrValue, SDBracketLevel, CurrTier)
  2970. }
  2971. Else
  2972. {
  2973. ValueRange := LookupAffixData("data\SpellDamage_1H.txt", ItemLevel, CurrValue, SDBracketLevel, CurrTier)
  2974. }
  2975. ValueRange := StrPad(ValueRange, ValueRangeFieldWidth, "left")
  2976. }
  2977. Else
  2978. {
  2979. msgbox, %MsgUnhandled%
  2980. ValueRange := StrPad("n/a", ValueRangeFieldWidth, "left")
  2981. }
  2982. }
  2983. Else
  2984. {
  2985. SpellDamageBracketFromComp := LookupAffixBracket("data\SpellDamage_MaxMana_1H.txt", MMBracketLevel)
  2986. SDValueRest := CurrValue - RangeMid(SpellDamageBracketFromComp)
  2987. SpellDamageBracket := LookupAffixBracket("data\SpellDamage_1H.txt", ItemLevel, SDValueRest, SDBracketLevel)
  2988. ValueRange := AddRange(SpellDamageBracket, SpellDamageBracketFromComp)
  2989. ValueRange := MarkAsGuesstimate(ValueRange)
  2990. }
  2991. }
  2992. Else
  2993. {
  2994. ValueRange := LookupAffixData("data\SpellDamage_MaxMana_1H.txt", ItemLevel, CurrValue, BracketLevel, CurrTier)
  2995. MaxManaBracket := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", BracketLevel)
  2996. AffixType := "Comp. Prefix"
  2997. }
  2998. }
  2999. ; if MaxManaValue falls within bounds of MaxManaBracket this means the max mana value is already fully accounted for
  3000. If (WithinBounds(MaxManaBracket, MaxManaValue))
  3001. {
  3002. MaxManaPartial =
  3003. }
  3004. Else
  3005. {
  3006. MaxManaPartial := MaxManaBracket
  3007. }
  3008. }
  3009. Else
  3010. {
  3011. If (ItemSubType == "Amulet")
  3012. {
  3013. ValueRange := LookupAffixData("data\SpellDamage_Amulets.txt", ItemLevel, CurrValue, "", CurrTier)
  3014. }
  3015. Else
  3016. {
  3017. If (ItemSubType == "Staff")
  3018. {
  3019. ValueRange := LookupAffixData("data\SpellDamage_Staff.txt", ItemLevel, CurrValue, "", CurrTier)
  3020. }
  3021. Else
  3022. {
  3023. ValueRange := LookupAffixData("data\SpellDamage_1H.txt", ItemLevel, CurrValue, "", CurrTier)
  3024. }
  3025. }
  3026. NumPrefixes += 1
  3027. }
  3028. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3029. Continue
  3030. }
  3031.  
  3032. ; "Base Maximum Mana" (simple prefix)
  3033. ; "1H Spell Damage" / "Base Maximum Mana" (complex prefix)
  3034. ; "Staff Spell Damage" / "Base Maximum Mana" (complex prefix)
  3035. IfInString, A_LoopField, maximum Mana
  3036. {
  3037. AffixType := "Prefix"
  3038. If (ItemBaseType == "Weapon")
  3039. {
  3040. If (HasSpellDamage)
  3041. {
  3042. If (MaxManaPartial and Not WithinBounds(MaxManaPartial, CurrValue))
  3043. {
  3044. ; msgbox, MaxManaPartial: %MaxManaPartial%
  3045. NumPrefixes += 1
  3046. AffixType := "Comp. Prefix+Prefix"
  3047.  
  3048. ValueRange := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", ItemLevel, CurrValue)
  3049. MaxManaRest := CurrValue-RangeMid(MaxManaPartial)
  3050.  
  3051. ; msgbox, MaxManaPartial: %MaxManaPartial%
  3052. ; msgbox, MaxManaRest: %MaxManaRest%
  3053. If (MaxManaRest >= 15) ; 15 because the lowest possible value at this time for Max Mana is 15 at bracket level 1
  3054. {
  3055. ; Lookup remaining Max Mana bracket that comes from Max Mana being concatenated as simple prefix
  3056. ValueRange1 := LookupAffixBracket("data\MaxMana.txt", ItemLevel, MaxManaRest)
  3057. ValueRange2 := MaxManaPartial
  3058. ; msgbox, MaxManaPartial: %MaxManaPartial%`, ValueRange1: %ValueRange1%`, ValueRange2: %ValueRange2%
  3059.  
  3060. ; Add these ranges together to get an estimated range
  3061. ValueRange := AddRange(ValueRange1, ValueRange2)
  3062. ValueRange := MarkAsGuesstimate(ValueRange)
  3063. }
  3064. Else
  3065. {
  3066. ; Could be that the spell damage affix is actually a pure spell damage affix
  3067. ; (w/o the added max mana) so this would mean max mana is a pure prefix - if
  3068. ; NumPrefixes allows it, ofc...
  3069. If (NumPrefixes < 3)
  3070. {
  3071. AffixType := "Prefix"
  3072. ValueRange := LookupAffixData("data\MaxMana.txt", ItemLevel, CurrValue, "", CurrTier)
  3073. ChangeAffixDetailLine("increased Spell Damage", "Comp. Prefix", "Prefix")
  3074. }
  3075. }
  3076. }
  3077. Else
  3078. {
  3079. ; it's on a weapon, there is Spell Damage but no MaxManaPartial or NumPrefixes already is 3
  3080. AffixType := "Comp. Prefix"
  3081. ValueRange := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", ItemLevel, CurrValue)
  3082. If (Not IsValidBracket(ValueRange))
  3083. {
  3084. ; incr. spell damage is actually a prefix and not a comp. prefix
  3085. ; so max mana must be a normal prefix as well then
  3086. AffixType := "Prefix"
  3087. ValueRange := LookupAffixData("data\MaxMana.txt", ItemLevel, CurrValue, "", CurrTier)
  3088. }
  3089. Else
  3090. {
  3091. ValueRange := MarkAsGuesstimate(ValueRange)
  3092. }
  3093. }
  3094. ; check if we still need to increment for the Spell Damage part
  3095. If (NumPrefixes < 3)
  3096. {
  3097. NumPrefixes += 1
  3098. }
  3099. }
  3100. Else
  3101. {
  3102. ; it's on a weapon but there is no Spell Damage, which makes it a simple prefix
  3103. Goto, SimpleMaxManaPrefix
  3104. }
  3105. }
  3106. Else
  3107. {
  3108. ; Armour...
  3109. ; Max Mana cannot appear on belts but I won't exclude them for now
  3110. ; to future-proof against when max mana on belts might be added.
  3111. Goto, SimpleMaxManaPrefix
  3112. }
  3113.  
  3114. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3115. Continue
  3116.  
  3117. SimpleMaxManaPrefix:
  3118. NumPrefixes += 1
  3119. ValueRange := LookupAffixData("data\MaxMana.txt", ItemLevel, CurrValue, "", CurrTier)
  3120. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3121. Continue
  3122. }
  3123.  
  3124. ; "Local Physical Damage +%" (simple prefix)
  3125. ; "Local Physical Damage +%" / "Local Accuracy Rating" (complex prefix)
  3126. ; only on Weapons
  3127. ; needs to come before Accuracy Rating stuff
  3128. IfInString, A_LoopField, increased Physical Damage
  3129. {
  3130. AffixType := "Prefix"
  3131. IPDPath := "data\IncrPhysDamage.txt"
  3132. If (HasToAccuracyRating)
  3133. {
  3134. ARIPDPath := "data\AccuracyRating_IncrPhysDamage.txt"
  3135. IPDARPath := "data\IncrPhysDamage_AccuracyRating.txt"
  3136. ARValue := ExtractValueFromAffixLine(ItemDataChunk, "to Accuracy Rating")
  3137. ARPath := "data\AccuracyRating_Global.txt"
  3138. If (ItemBaseType == "Weapon")
  3139. {
  3140. ARPath := "data\AccuracyRating_Local.txt"
  3141. }
  3142.  
  3143. ; look up IPD bracket, and use its bracket level to cross reference the corresponding
  3144. ; AR bracket. If both check out (are within bounds of their bracket level) case is
  3145. ; simple: Comp. Prefix (IPD / AR)
  3146. IPDBracketLevel := 0
  3147. IPDBracket := LookupAffixBracket(IPDARPath, ItemLevel, CurrValue, IPDBracketLevel)
  3148. ARBracket := LookupAffixBracket(ARIPDPath, IPDBracketLevel)
  3149.  
  3150. If (HasIncrLightRadius)
  3151. {
  3152. LRValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Light Radius")
  3153. ; first check if the AR value that comes with the Comp. Prefix AR / Light Radius
  3154. ; already covers the complete AR value. If so, from that follows that the Incr.
  3155. ; Phys Damage value can only be a Damage Scaling prefix.
  3156. LRBracketLevel := 0
  3157. LRBracket := LookupAffixBracket("data\LightRadius_AccuracyRating.txt", ItemLevel, LRValue, LRBracketLevel)
  3158. ARLRBracket := LookupAffixBracket("data\AccuracyRating_LightRadius.txt", LRBracketLevel)
  3159. If (IsValidBracket(ARLRBracket))
  3160. {
  3161. If (WithinBounds(ARLRBracket, ARValue) AND WithinBounds(IPDBracket, CurrValue))
  3162. {
  3163. ;msgbox, LRBracketLevel: %LRBracketLevel%, ARLRBracket: %ARLRBracket%
  3164. Goto, SimpleIPDPrefix
  3165. }
  3166. }
  3167. }
  3168.  
  3169. ; msgbox, IPDBracket: %IPDBracket%`, ARBracket: %ARBracket%
  3170.  
  3171. If (IsValidBracket(IPDBracket) and IsValidBracket(ARBracket))
  3172. {
  3173. Goto, CompIPDARPrefix
  3174. }
  3175.  
  3176. If (Not IsValidBracket(IPDBracket))
  3177. {
  3178. IPDBracket := LookupAffixBracket(IPDPath, ItemLevel, CurrValue)
  3179. ARBracket := LookupAffixBracket(ARPath, ItemLevel, ARValue) ; also lookup AR as if it were a simple suffix
  3180. ; msgbox, NumPrefixes: %NumPrefixes%, NumSuffixes: %NumSuffixes%, IPDBracket: %IPDBracket%, ARBracket: %ARBracket%
  3181. If (IsValidBracket(IPDBracket) and IsValidBracket(ARBracket) and NumPrefixes < 3)
  3182. {
  3183. HasIncrPhysDmg := 0
  3184. Goto, SimpleIPDPrefix
  3185. }
  3186. ARBracketLevel := 0
  3187. ARBracket := LookupAffixBracket(ARIPDPath, ItemLevel, ARValue, ARBracketLevel)
  3188. If (IsValidBracket(ARBracket))
  3189. {
  3190. IPDARBracket := LookupAffixBracket(IPDARPath, ARBracketLevel)
  3191. IPDRest := CurrValue - RangeMid(IPDARBracket)
  3192. IPDBracket := LookupAffixBracket(IPDPath, ItemLevel, IPDRest)
  3193. ValueRange := AddRange(IPDARBracket, IPDBracket)
  3194. ValueRange := MarkAsGuesstimate(ValueRange)
  3195. ARAffixTypePartial := "Comp. Prefix"
  3196. Goto, CompIPDARPrefixPrefix
  3197. }
  3198. }
  3199.  
  3200. If ((Not IsValidBracket(IPDBracket)) and (Not IsValidBracket(ARBracket)))
  3201. {
  3202. HasIncrPhysDmg := 0
  3203. Goto, CompIPDARPrefix
  3204. }
  3205.  
  3206. If (IsValidBracket(ARBracket))
  3207. {
  3208. ; AR bracket not found in the composite IPD/AR table
  3209. ARValue := ExtractValueFromAffixLine(ItemDataChunk, "to Accuracy Rating")
  3210. ARBracket := LookupAffixBracket(ARPath, ItemLevel, ARValue)
  3211.  
  3212. Goto, CompIPDARPrefix
  3213. }
  3214. If (IsValidBracket(IPDBracket))
  3215. {
  3216. ; AR bracket was found in the comp. IPD/AR table, but not the IPD bracket
  3217. Goto, SimpleIPDPrefix
  3218. }
  3219. Else
  3220. {
  3221. ValueRange := LookupAffixData(IPDPath, ItemLevel, CurrValue, "", CurrTier)
  3222. }
  3223. }
  3224. Else
  3225. {
  3226. Goto, SimpleIPDPrefix
  3227. }
  3228.  
  3229. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3230. Continue
  3231.  
  3232. SimpleIPDPrefix:
  3233. NumPrefixes += 1
  3234. ValueRange := LookupAffixData("data\IncrPhysDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  3235. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3236. Continue
  3237. CompIPDARPrefix:
  3238. AffixType := "Comp. Prefix"
  3239. ValueRange := LookupAffixData(IPDARPath, ItemLevel, CurrValue, "", CurrTier)
  3240. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3241. ARPartial := ARBracket
  3242. Continue
  3243. CompIPDARPrefixPrefix:
  3244. NumPrefixes += 1
  3245. AffixType := "Comp. Prefix+Prefix"
  3246. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3247. ARPartial := ARBracket
  3248. Continue
  3249. }
  3250.  
  3251. IfInString, A_LoopField, increased Block and Stun Recovery
  3252. {
  3253. AffixType := "Prefix"
  3254. If (HasHybridDefences)
  3255. {
  3256. AffixType := "Comp. Prefix"
  3257. BSRecAffixPath := "data\StunRecovery_Hybrid.txt"
  3258. BSRecAffixBracket := LookupAffixBracket(BSRecAffixPath, ItemLevel, CurrValue)
  3259. If (Not IsValidBracket(BSRecAffixBracket))
  3260. {
  3261. CompStatAffixType =
  3262. If (HasIncrArmourAndEvasion)
  3263. {
  3264. PartialAffixString := "increased Armour and Evasion"
  3265. }
  3266. If (HasIncrEvasionAndES)
  3267. {
  3268. PartialAffixString := "increased Evasion and Energy Shield"
  3269. }
  3270. If (HasIncrArmourAndES)
  3271. {
  3272. PartialAffixString := "increased Armour and Energy Shield"
  3273. }
  3274. CompStatAffixType := GetAffixTypeFromProcessedLine(PartialAffixString)
  3275. If (BSRecPartial)
  3276. {
  3277. ; msgbox, NumPrefixes: %NumPrefixes%`, NumSuffixes: %NumSuffixes%`, BSRest: %BSRest%`, BSRecPartial: %BSRecPartial%
  3278. If (WithinBounds(BSRecPartial, CurrValue))
  3279. {
  3280. IfInString, CompStatAffixType, Comp. Prefix
  3281. {
  3282. AffixType := CompStatAffixType
  3283. }
  3284. }
  3285. Else
  3286. {
  3287. If (NumSuffixes < 3)
  3288. {
  3289. AffixType := "Comp. Prefix+Suffix"
  3290. BSRest := CurrValue - RangeMid(BSRecPartial)
  3291. BSRecAffixBracket := LookupAffixBracket("data\StunRecovery_Suffix.txt", ItemLevel, BSRest)
  3292. If (Not IsValidBracket(BSRecAffixBracket))
  3293. {
  3294. AffixType := "Comp. Prefix+Prefix"
  3295. BSRecAffixBracket := LookupAffixBracket("data\StunRecovery_Prefix.txt", ItemLevel, CurrValue)
  3296. If (Not IsValidBracket(BSRecAffixBracket))
  3297. {
  3298. If (CompStatAffixType == "Comp. Prefix+Prefix" and NumSuffixes < 3)
  3299. {
  3300. AffixType := "Comp. Prefix+Suffix"
  3301. BSRecSuffixBracket := LookupAffixBracket("data\StunRecovery_Suffix.txt", ItemLevel, BSRest)
  3302. NumSuffixes += 1
  3303. If (Not IsValidBracket(BSRecSuffixBracket))
  3304. {
  3305. ; TODO: properly deal with this quick fix!
  3306. ;
  3307. ; if this point is reached this means that the parts that give to
  3308. ; increased armor/evasion/es/hybrid + stun recovery need to fully be
  3309. ; re-evaluated.
  3310. ;
  3311. ; take an ilvl 62 item with these 2 lines:
  3312. ;
  3313. ; 118% increased Armour and Evasion
  3314. ; 24% increased Block and Stun Recovery
  3315. ;
  3316. ; Since it's ilvl 62, we assume the hybrid + stun recovery bracket to be the
  3317. ; highest possible (lvl 60 bracket), which is 42-50. So that's max 50 of the
  3318. ; 118 dealth with.
  3319. ; Consequently, that puts the stun recovery partial at 14-15 for the lvl 60 bracket.
  3320. ; This now leaves, 68 of hybrid defence to account for, which we can do by assuming
  3321. ; the remainder to come from a hybrid defence prefix. So that's incr. Armour and Evasion
  3322. ; identified as CP+P
  3323. ; However, here come's the problem, our lvl 60 bracket had 14-15 stun recovery which
  3324. ; assuming max, leaves 9 remainder (24-15) to account for. Should be easy, right?
  3325. ; Just assume the rest comes from a stun recovery suffix and look it up. Except the
  3326. ; lowest possible entry for a stun recovery suffix is 11! Leaving us with the issues that
  3327. ; we know that CP+P is right for the hybrid + stun recovery line and CP+S is right for the
  3328. ; stun recovery line.
  3329. ; Most likely, what is wrong is the assumption earlier to take the highest possible
  3330. ; hybrid + stun recovery bracket. Problem is that wasn't apparent when hybrid defences
  3331. ; was processed.
  3332. ; At this point, a quick fix what I am doing is I just look up the complete stun recovery
  3333. ; value as if it were a suffix completely but still mark it as CP+S.
  3334. ; To deal with this correctly I would need to reprocess the hybrid + stun recovery line here
  3335. ; with a different ratio of the CP part to the P part to get a lower BSRecPartial.
  3336. ;
  3337. BSRecSuffixBracket := LookupAffixBracket("data\StunRecovery_Suffix.txt", ItemLevel, CurrValue)
  3338. ValueRange := LookupAffixBracket("data\StunRecovery_Suffix.txt", ItemLevel, CurrValue)
  3339. ValueRange := MarkAsGuesstimate(ValueRange)
  3340. }
  3341. Else
  3342. {
  3343. ValueRange := AddRange(BSRecSuffixBracket, BSRecPartial)
  3344. ValueRange := MarkAsGuesstimate(ValueRange)
  3345. }
  3346. }
  3347. Else
  3348. {
  3349. AffixType := "Suffix"
  3350. ValueRange := LookupAffixData("data\StunRecovery_Suffix.txt", ItemLevel, CurrValue, "", CurrTier)
  3351. If (NumSuffixes < 3)
  3352. {
  3353. NumSuffixes += 1
  3354. }
  3355. ChangeAffixDetailLine(PartialAffixString, "Comp. Prefix" , "Prefix")
  3356. }
  3357. }
  3358. Else
  3359. {
  3360. If (NumPrefixes < 3)
  3361. {
  3362. NumPrefixes += 1
  3363. }
  3364. }
  3365. }
  3366. Else
  3367. {
  3368. NumSuffixes += 1
  3369. ValueRange := AddRange(BSRecPartial, BSRecAffixBracket)
  3370. ValueRange := MarkAsGuesstimate(ValueRange)
  3371. }
  3372. }
  3373. }
  3374. }
  3375. }
  3376. Else
  3377. {
  3378. ; msgbox, % CurrValue
  3379. ValueRange := LookupAffixData(BSRecAffixPath, ItemLevel, CurrValue, "", CurrTier)
  3380. }
  3381. }
  3382. Else
  3383. {
  3384. AffixType := "Comp. Prefix"
  3385. If (HasIncrArmour)
  3386. {
  3387. PartialAffixString := "increased Armour"
  3388. BSRecAffixPath := "data\StunRecovery_Armour.txt"
  3389. }
  3390. If (HasIncrEvasion)
  3391. {
  3392. PartialAffixString := "increased Evasion Rating"
  3393. BSRecAffixPath := "data\StunRecovery_Evasion.txt"
  3394. }
  3395. If (HasIncrEnergyShield)
  3396. {
  3397. PartialAffixString := "increased Energy Shield"
  3398. BSRecAffixPath := "data\StunRecovery_EnergyShield.txt"
  3399. }
  3400. BSRecAffixBracket := LookupAffixBracket(BSRecAffixPath, ItemLevel, CurrValue)
  3401. If (Not IsValidBracket(BSRecAffixBracket))
  3402. {
  3403. CompStatAffixType := GetAffixTypeFromProcessedLine(PartialAffixString)
  3404. If (BSRecPartial)
  3405. {
  3406. If (WithinBounds(BSRecPartial, CurrValue))
  3407. {
  3408. IfInString, CompStatAffixType, Comp. Prefix
  3409. {
  3410. AffixType := CompStatAffixType
  3411. }
  3412. }
  3413. Else
  3414. {
  3415. If (NumSuffixes < 3)
  3416. {
  3417. AffixType := "Comp. Prefix+Suffix"
  3418. BSRest := CurrValue - RangeMid(BSRecPartial)
  3419. BSRecAffixBracket := LookupAffixBracket("data\StunRecovery_Suffix.txt", ItemLevel, BSRest)
  3420. If (Not IsValidBracket(BSRecAffixBracket))
  3421. {
  3422. AffixType := "Comp. Prefix+Prefix"
  3423. BSRecAffixBracket := LookupAffixBracket("data\StunRecovery_Prefix.txt", ItemLevel, CurrValue)
  3424. If (Not IsValidBracket(BSRecAffixBracket))
  3425. {
  3426. AffixType := "Suffix"
  3427. ValueRange := LookupAffixData("data\StunRecovery_Suffix.txt", ItemLevel, CurrValue, "", CurrTier)
  3428. If (NumSuffixes < 3)
  3429. {
  3430. NumSuffixes += 1
  3431. }
  3432. ChangeAffixDetailLine(PartialAffixString, "Comp. Prefix" , "Prefix")
  3433. }
  3434. Else
  3435. {
  3436. If (NumPrefixes < 3)
  3437. {
  3438. NumPrefixes += 1
  3439. }
  3440. }
  3441.  
  3442. }
  3443. Else
  3444. {
  3445. NumSuffixes += 1
  3446. ValueRange := AddRange(BSRecPartial, BSRecAffixBracket)
  3447. ValueRange := MarkAsGuesstimate(ValueRange)
  3448. }
  3449. }
  3450. }
  3451. }
  3452. Else
  3453. {
  3454. BSRecSuffixPath := "data\StunRecovery_Suffix.txt"
  3455. BSRecSuffixBracket := LookupAffixBracket(BSRecSuffixPath, ItemLevel, CurrValue)
  3456. If (IsValidBracket(BSRecSuffixBracket))
  3457. {
  3458. AffixType := "Suffix"
  3459. ValueRange := LookupAffixData(BSRecSuffixPath, ItemLevel, CurrValue, "", CurrTier)
  3460. If (NumSuffixes < 3)
  3461. {
  3462. NumSuffixes += 1
  3463. }
  3464. }
  3465. Else
  3466. {
  3467. BSRecPrefixPath := "data\StunRecovery_Prefix.txt"
  3468. BSRecPrefixBracket := LookupAffixBracket(BSRecPrefixPath, ItemLevel, CurrValue)
  3469. ValueRange := LookupAffixData(BSRecPrefixPath, ItemLevel, CurrValue, "", CurrTier)
  3470. }
  3471. }
  3472. }
  3473. Else
  3474. {
  3475. ; msgbox, BSRecAffixBracket: %BSRecAffixBracket%
  3476. ValueRange := LookupAffixData(BSRecAffixPath, ItemLevel, CurrValue, "", CurrTier)
  3477. }
  3478. }
  3479. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3480. Continue
  3481. }
  3482.  
  3483. ; AR is one tough beast... currently there are the following affixes affecting AR:
  3484. ; 1) "Accuracy Rating" (Suffix)
  3485. ; 2) "Local Accuracy Rating" (Suffix)
  3486. ; 3) "Light Radius / + Accuracy Rating" (Suffix) - only the first 2 entries, bc last entry combines LR with #% increased Accuracy Rating instead!
  3487. ; 4) "Local Physical Dmg +% / Local Accuracy Rating" (Prefix)
  3488.  
  3489. ; the difficulty lies in those cases that combine multiple of these affixes into one final display value
  3490. ; currently I try and tackle this by using a trickle-through partial balance approach. That is, go from
  3491. ; most special case to most normal, while subtracting the value that each case most likely contributes
  3492. ; until you have a value left that can be found in the most nominal case
  3493. ;
  3494. ; Important to note here:
  3495. ; ARPartial will be set during the "increased Physical Damage" case above
  3496.  
  3497. IfInString, A_LoopField, to Accuracy Rating
  3498. {
  3499. ; trickle-through order:
  3500. ; 1) increased AR, Light Radius, all except Belts, Comp. Suffix
  3501. ; 2) to AR, Light Radius, all except Belts, Comp. Suffix
  3502. ; 3) increased Phys Damage, to AR, Weapons, Prefix
  3503. ; 4) to AR, all except Belts, Suffix
  3504.  
  3505. ValueRangeAR := "0-0"
  3506. AffixType := ""
  3507. IPDAffixType := GetAffixTypeFromProcessedLine("increased Physical Damage")
  3508. If (HasIncrLightRadius and Not HasIncrAccuracyRating)
  3509. {
  3510. ; "of Shining" and "of Light"
  3511. LightRadiusValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Light Radius")
  3512.  
  3513. ; get bracket level of the light radius so we can look up the corresponding AR bracket
  3514. BracketLevel := 0
  3515. LookupAffixBracket("data\LightRadius_AccuracyRating.txt", ItemLevel, LightRadiusValue, BracketLevel)
  3516. ARLRBracket := LookupAffixBracket("data\AccuracyRating_LightRadius.txt", BracketLevel)
  3517.  
  3518. AffixType := AffixType . "Comp. Suffix"
  3519. ValueRange := LookupAffixData("data\AccuracyRating_LightRadius.txt", ItemLevel, CurrValue, "", CurrTier)
  3520. NumSuffixes += 1
  3521.  
  3522. If (ARPartial)
  3523. {
  3524. ; append this affix' contribution to our partial AR range
  3525. ARPartial := AddRange(ARPartial, ARLRBracket)
  3526. }
  3527. ; msgbox, ARLRBracket: %ARLRBracket%, ARPartial: %ARPartial%
  3528. ; test if candidate range already covers current AR value
  3529. If (WithinBounds(ARLRBracket, CurrValue))
  3530. {
  3531. Goto, FinalizeAR
  3532. }
  3533. Else
  3534. {
  3535. AffixType := "Comp. Suffix+Suffix"
  3536. If (HasIncrPhysDmg)
  3537. {
  3538. If (ARPartial)
  3539. {
  3540. CombinedRange := AddRange(ARLRBracket, ARPartial)
  3541. ; msgbox, CombinedRange: %CombinedRange%
  3542. AffixType := "Comp. Prefix+Comp. Suffix"
  3543. If (WithinBounds(CombinedRange, CurrValue))
  3544. {
  3545. If (NumPrefixes < 3)
  3546. {
  3547. NumPrefixes += 1
  3548. }
  3549. ValueRange := CombinedRange
  3550. ValueRange := MarkAsGuesstimate(ValueRange)
  3551. Goto, FinalizeAR
  3552. }
  3553. Else
  3554. {
  3555. NumSuffixes -= 1
  3556. }
  3557. }
  3558.  
  3559. ; msgbox, IPDAffixType: %IPDAffixType%
  3560. If (InStr(IPDAffixType, "Comp. Prefix"))
  3561. {
  3562. ; AffixType := "Comp. Prefix+Comp. Suffix+Suffix"
  3563. If (NumPrefixes < 3)
  3564. {
  3565. NumPrefixes += 1
  3566. }
  3567. }
  3568. }
  3569. ARRest := CurrValue - RangeMid(ARLRBracket)
  3570. ARBracket := LookupAffixBracket("data\AccuracyRating_Global.txt", ItemLevel, ARRest)
  3571. ValueRange := AddRange(ARBracket, ARLRBracket)
  3572. ValueRange := MarkAsGuesstimate(ValueRange)
  3573. NumSuffixes += 1
  3574. Goto, FinalizeAR
  3575. }
  3576. }
  3577. If (ItemBaseType == "Weapon" and HasIncrPhysDmg)
  3578. {
  3579. ; this is one of the trickiest cases currently: if this If-construct is reached that means the item has
  3580. ; multiple composites - "To Accuracy Rating / Increased Light Radius" and "Increased Physical Damage
  3581. ; / To Accuracy Rating". On top of that it might also contain part "To Accuracy Rating" suffix, all of
  3582. ; which are concatenated into one single "to Accuracy Rating" entry. Currently it handles most cases,
  3583. ; if not all, but I still have a feeling I am missing something...
  3584. If (ARPartial)
  3585. {
  3586. If (WithinBounds(ARPartial, CurrValue))
  3587. {
  3588. AffixType := "Comp. Prefix"
  3589. If (NumPrefixes < 3)
  3590. {
  3591. NumPrefixes += 1
  3592. }
  3593. ValueRange := LookupAffixData("data\AccuracyRating_IncrPhysDamage.txt", ItemLevel, RangeMid(ARPartial), "", CurrTier)
  3594. Goto, FinalizeAR
  3595. }
  3596.  
  3597. ARPartialMid := RangeMid(ARPartial)
  3598. ARRest := CurrValue - ARPartialMid
  3599. If (ItemSubType == "Mace" and ItemGripType == "2H")
  3600. {
  3601. ARBracket := LookupAffixBracket("data\AccuracyRating_Global.txt", ItemLevel, ARRest)
  3602. }
  3603. Else
  3604. {
  3605. ARBracket := LookupAffixBracket("data\AccuracyRating_Local.txt", ItemLevel, ARRest)
  3606. }
  3607.  
  3608. ; msgbox, ItemLevel: %ItemLevel%`, ARRest: %ARRest%`, ARBracket: %ARBracket%`, ARPartial: %ARPartial%
  3609.  
  3610. If (IsValidBracket(ARBracket))
  3611. {
  3612. AffixType := "Comp. Prefix+Suffix"
  3613. If (NumSuffixes < 3)
  3614. {
  3615. NumSuffixes += 1
  3616. }
  3617. Else
  3618. {
  3619. AffixType := "Comp. Prefix"
  3620. If (NumPrefixes < 3)
  3621. {
  3622. NumPrefixes += 2
  3623. }
  3624. }
  3625. NumPrefixes += 1
  3626. ; msgbox, ARBracket: %ARBracket%`, ARPartial: %ARPartial%
  3627. ValueRange := AddRange(ARBracket, ARPartial)
  3628. ValueRange := MarkAsGuesstimate(ValueRange)
  3629.  
  3630. Goto, FinalizeAR
  3631. }
  3632. }
  3633. Else
  3634. {
  3635. ActualValue := CurrValue
  3636. }
  3637.  
  3638. ValueRangeAR := LookupAffixBracket("data\AccuracyRating_Global.txt", ItemLevel, ActualValue)
  3639. If (IsValidBracket(ValueRangeAR))
  3640. {
  3641. If (NumPrefixes >= 3)
  3642. {
  3643. AffixType := "Suffix"
  3644. If (NumSuffixes < 3)
  3645. {
  3646. NumSuffixes += 1
  3647. }
  3648. ValueRange := LookupAffixData("data\AccuracyRating_Local.txt", ItemLevel, ActualValue, "", CurrTier)
  3649. }
  3650. Else
  3651. {
  3652. IfInString, IPDAffixType, Comp. Prefix
  3653. {
  3654. AffixType := "Comp. Prefix"
  3655. }
  3656. Else
  3657. {
  3658. AffixType := "Prefix"
  3659. }
  3660. NumPrefixes += 1
  3661. }
  3662. Goto, FinalizeAR
  3663. }
  3664. Else
  3665. {
  3666. ARValueRest := CurrValue - (RangeMid(ValueRangeAR))
  3667. If (HasIncrLightRadius and Not HasIncrAccuracyRating)
  3668. {
  3669. AffixType := "Comp. Prefix+Comp. Suffix+Suffix"
  3670. }
  3671. Else
  3672. {
  3673. AffixType := "Comp. Prefix+Suffix"
  3674. }
  3675. NumPrefixes += 1
  3676. NumSuffixes += 1
  3677. ; ValueRange := LookupAffixData("data\AccuracyRating_IncrPhysDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  3678. ValueRange := AddRange(ARPartial, ValueRangeAR)
  3679. ValueRange := MarkAsGuesstimate(ValueRange)
  3680. }
  3681. ; NumPrefixes should be incremented already by "increased Physical Damage" case
  3682. Goto, FinalizeAR
  3683. }
  3684. AffixType := "Suffix"
  3685. ValueRange := LookupAffixData("data\AccuracyRating_Global.txt", ItemLevel, CurrValue, "", CurrTier)
  3686. NumSuffixes += 1
  3687. Goto, FinalizeAR
  3688.  
  3689. FinalizeAR:
  3690. If (StrLen(ARAffixTypePartial) > 0 AND (Not InStr(AffixType, ARAffixTypePartial)))
  3691. {
  3692. AffixType := ARAffixTypePartial . "+" . AffixType
  3693. If (InStr(ARAffixTypePartial, "Prefix") AND NumPrefixes < 3)
  3694. {
  3695. NumPrefixes += 1
  3696. }
  3697. Else If (InStr(ARAffixTypePartial, "Suffix") AND NumSuffixes < 3)
  3698. {
  3699. NumSuffixes += 1
  3700. }
  3701. ARAffixTypePartial =
  3702. }
  3703. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3704. Continue
  3705. }
  3706.  
  3707. IfInString, A_LoopField, increased Rarity
  3708. {
  3709. ActualValue := CurrValue
  3710. If (NumSuffixes <= 3)
  3711. {
  3712. ValueRange := LookupAffixBracket("data\IIR_Suffix.txt", ItemLevel, ActualValue)
  3713. ValueRangeAlt := LookupAffixBracket("data\IIR_Prefix.txt", ItemLevel, ActualValue)
  3714. }
  3715. Else
  3716. {
  3717. ValueRange := LookupAffixBracket("data\IIR_Prefix.txt", ItemLevel, ActualValue)
  3718. ValueRangeAlt := LookupAffixBracket("data\IIR_Suffix.txt", ItemLevel, ActualValue)
  3719. }
  3720. If (Not IsValidBracket(ValueRange))
  3721. {
  3722. If (Not IsValidBracket(ValueRangeAlt))
  3723. {
  3724. NumPrefixes += 1
  3725. NumSuffixes += 1
  3726. ; try to reverse engineer composition of both ranges
  3727. PrefixDivisor := 1
  3728. SuffixDivisor := 1
  3729. Loop
  3730. {
  3731. ValueRangeSuffix := LookupAffixBracket("data\IIR_Suffix.txt", ItemLevel, Floor(ActualValue/SuffixDivisor))
  3732. ValueRangePrefix := LookupAffixBracket("data\IIR_Prefix.txt", ItemLevel, Floor(ActualValue/PrefixDivisor))
  3733. If (Not IsValidBracket(ValueRangeSuffix))
  3734. {
  3735. SuffixDivisor += 0.25
  3736. }
  3737. If (Not IsValidBracket(ValueRangePrefix))
  3738. {
  3739. PrefixDivisor += 0.25
  3740. }
  3741. If ((IsValidBracket(ValueRangeSuffix)) and (IsValidBracket(ValueRangePrefix)))
  3742. {
  3743. Break
  3744. }
  3745. }
  3746. ValueRange := AddRange(ValueRangePrefix, ValueRangeSuffix)
  3747. Goto, FinalizeIIRAsPrefixAndSuffix
  3748. }
  3749. Else
  3750. {
  3751. ValueRange := ValueRangePrefix
  3752. Goto, FinalizeIIRAsPrefix
  3753. }
  3754. }
  3755. Else
  3756. {
  3757. If (NumSuffixes >= 3) {
  3758. Goto, FinalizeIIRAsPrefix
  3759. }
  3760. Goto, FinalizeIIRAsSuffix
  3761. }
  3762.  
  3763. FinalizeIIRAsPrefix:
  3764. NumPrefixes += 1
  3765. ValueRange := LookupAffixData("data\IIR_Prefix.txt", ItemLevel, ActualValue, "", CurrTier)
  3766. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  3767. Continue
  3768.  
  3769. FinalizeIIRAsSuffix:
  3770. NumSuffixes += 1
  3771. ValueRange := LookupAffixData("data\IIR_Suffix.txt", ItemLevel, ActualValue, "", CurrTier)
  3772. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  3773. Continue
  3774.  
  3775. FinalizeIIRAsPrefixAndSuffix:
  3776. ValueRange := MarkAsGuesstimate(ValueRange)
  3777. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix+Suffix", ValueRange, CurrTier), A_Index)
  3778. Continue
  3779. }
  3780. }
  3781. }
  3782.  
  3783. ; change a detail line that was already processed and added to the
  3784. ; AffixLines "stack". This can be used for example to change the
  3785. ; affix type when more is known about a possible affix combo.
  3786. ; For example with a IPD / AR combo, if IPD was thought to be a
  3787. ; prefix but later (when processing AR) found to be a composite
  3788. ; prefix.
  3789. ChangeAffixDetailLine(PartialAffixString, SearchRegex, ReplaceRegex)
  3790. {
  3791. Global
  3792. Loop, %NumAffixLines%
  3793. {
  3794. CurAffixLine := AffixLines%A_Index%
  3795. IfInString, CurAffixLine, %PartialAffixString%
  3796. {
  3797. local NewLine
  3798. NewLine := RegExReplace(CurAffixLine, SearchRegex, ReplaceRegex)
  3799. AffixLines%A_Index% := NewLine
  3800. return True
  3801. }
  3802. }
  3803. return False
  3804. }
  3805.  
  3806. ExtractValueFromAffixLine(ItemDataChunk, PartialAffixString)
  3807. {
  3808. Loop, Parse, ItemDataChunk, `n, `r
  3809. {
  3810. If StrLen(A_LoopField) = 0
  3811. {
  3812. Break ; not interested in blank lines
  3813. }
  3814. IfInString, ItemDataChunk, Unidentified
  3815. {
  3816. Break ; not interested in unidentified items
  3817. }
  3818.  
  3819. CurrValue := GetActualValue(A_LoopField)
  3820.  
  3821. IfInString, A_LoopField, %PartialAffixString%
  3822. {
  3823. return CurrValue
  3824. }
  3825. }
  3826. }
  3827.  
  3828. ResetAffixDetailVars()
  3829. {
  3830. Global
  3831. NumPrefixes := 0
  3832. NumSuffixes := 0
  3833. TotalAffixes := 0
  3834. Loop, %NumAffixLines%
  3835. {
  3836. AffixLines%A_Index% =
  3837. }
  3838. Loop, 3
  3839. {
  3840. AffixLineParts%A_Index% =
  3841. }
  3842. }
  3843.  
  3844. IsEmptyString(String)
  3845. {
  3846. If (StrLen(String) == 0)
  3847. {
  3848. return True
  3849. }
  3850. Else
  3851. {
  3852. String := RegExReplace(String, "[\r\n ]", "")
  3853. If (StrLen(String) < 1)
  3854. {
  3855. return True
  3856. }
  3857. }
  3858. return False
  3859. }
  3860.  
  3861. PreProcessContents(CBContents)
  3862. {
  3863. ; place fixes for data inconsistencies here
  3864.  
  3865. ; I have not determined the reason for this, but a Heartbreaker - a unique - linked in chat
  3866. ; showed the following line below the Rarity: ... bit:
  3867. ; You cannot use this item. Its stats will be ignored. Please remove it.`n--------
  3868. ; This of course throws off subsequent parsing attempts so it is best to fix it beforehand.
  3869. Needle := "You cannot use this item. Its stats will be ignored. Please remove it.`r`n--------`r`n"
  3870. StringReplace, CBContents, CBContents, %Needle%,
  3871.  
  3872. return CBContents
  3873. }
  3874.  
  3875. PostProcessData(ParsedData)
  3876. {
  3877. Global CompactAffixTypes
  3878. If (CompactAffixTypes > 0)
  3879. {
  3880. StringReplace, TempResult, ParsedData, --------, ``, All
  3881. StringSplit, ParsedDataParts, TempResult, ``
  3882.  
  3883. NameAndDPSPart := ParsedDataParts1
  3884. SecondPart := ParsedDataParts2 ; total affix statistics for rare items or implicit mods for unique items
  3885. ThirdPart := ParsedDataParts3 ; affix composition for rare and unique items
  3886. FourthPart := ParsedDataParts4 ; Valuable line for unique items
  3887.  
  3888. ThirdPart := RegExReplace(ThirdPart, "Comp\. ", "C")
  3889. ThirdPart := RegExReplace(ThirdPart, "Suffix", "S")
  3890. ThirdPart := RegExReplace(ThirdPart, "Prefix", "P")
  3891.  
  3892. ParsedData := NameAndDPSPart
  3893. If (Not IsEmptyString(SecondPart)) ; two because of possible newline control chars
  3894. {
  3895. ParsedData := ParsedData . "--------" . SecondPart
  3896. }
  3897. If (Not IsEmptyString(ThirdPart))
  3898. {
  3899. ParsedData := ParsedData . "--------" . ThirdPart
  3900. }
  3901. If (Not IsEmptyString(FourthPart))
  3902. {
  3903. ParsedData := ParsedData . "--------" . FourthPart
  3904. }
  3905. }
  3906.  
  3907. return ParsedData
  3908. }
  3909.  
  3910. ParseClipBoardChanges()
  3911. {
  3912. Global PutResultsOnClipboard
  3913.  
  3914. CBContents := GetClipboardContents()
  3915. CBContents := PreProcessContents(CBContents)
  3916.  
  3917. ParsedData := ParseItemData(CBContents)
  3918. ParsedData := PostProcessData(ParsedData)
  3919.  
  3920. If (PutResultsOnClipboard > 0)
  3921. {
  3922. SetClipboardContents(ParsedData)
  3923. }
  3924. ShowToolTip(ParsedData)
  3925. }
  3926.  
  3927. AssembleDamageDetails(FullItemData)
  3928. {
  3929. PhysLo := 0
  3930. PhysHi := 0
  3931. Quality := 0
  3932. AttackSpeed := 0
  3933. PhysMult := 0
  3934. ChaoLo := 0
  3935. ChaoHi := 0
  3936. ColdLo := 0
  3937. ColdHi := 0
  3938. FireLo := 0
  3939. FireHi := 0
  3940. LighLo := 0
  3941. LighHi := 0
  3942.  
  3943. Loop, Parse, FullItemData, `n, `r
  3944. {
  3945. ; Get quality
  3946. IfInString, A_LoopField, Quality:
  3947. {
  3948. StringSplit, Arr, A_LoopField, %A_Space%, +`%
  3949. Quality := Arr2
  3950. Continue
  3951. }
  3952.  
  3953. ; Get total physical damage
  3954. IfInString, A_LoopField, Physical Damage:
  3955. {
  3956. ; IsWeapon := True
  3957. StringSplit, Arr, A_LoopField, %A_Space%
  3958. StringSplit, Arr, Arr3, -
  3959. PhysLo := Arr1
  3960. PhysHi := Arr2
  3961. Continue
  3962. }
  3963.  
  3964. ; Fix for Elemental damage only weapons. Like the Oro's Sacrifice
  3965. IfInString, A_LoopField, Elemental Damage:
  3966. {
  3967. Continue
  3968. }
  3969.  
  3970. ; Get attack speed
  3971. IfInString, A_LoopField, Attacks per Second:
  3972. {
  3973. StringSplit, Arr, A_LoopField, %A_Space%
  3974. AttackSpeed := Arr4
  3975. Continue
  3976. }
  3977.  
  3978. ; Get percentage physical damage increase
  3979. IfInString, A_LoopField, increased Physical Damage
  3980. {
  3981. StringSplit, Arr, A_LoopField, %A_Space%, `%
  3982. PhysMult := Arr1
  3983. Continue
  3984. }
  3985.  
  3986. ;Lines to skip fix for converted type damage. Like the Voltaxic Rift
  3987. IfInString, A_LoopField, Converted to
  3988. Goto, SkipDamageParse
  3989. IfInString, A_LoopField, can Shock
  3990. Goto, SkipDamageParse
  3991.  
  3992. ; Lines to skip for weapons that alter damage based on if equipped as
  3993. ; main or off hand. In that case skipp the off hand calc and just use
  3994. ; main hand as determining factor. Examples: Dyadus, Wings of Entropy
  3995. IfInString, A_LoopField, in Off Hand
  3996. Goto, SkipDamageParse
  3997.  
  3998. ; Parse elemental damage
  3999. ParseElementalDamage(A_LoopField, "Chaos", ChaoLo, ChaoHi)
  4000. ParseElementalDamage(A_LoopField, "Cold", ColdLo, ColdHi)
  4001. ParseElementalDamage(A_LoopField, "Fire", FireLo, FireHi)
  4002. ParseElementalDamage(A_LoopField, "Lightning", LighLo, LighHi)
  4003.  
  4004. SkipDamageParse:
  4005. DoNothing := True
  4006. }
  4007.  
  4008. Result =
  4009.  
  4010. SetFormat, FloatFast, 5.1
  4011. PhysDps := ((PhysLo + PhysHi) / 2) * AttackSpeed
  4012. EleDps := ((ChaoLo + ChaoHi + ColdLo + ColdHi + FireLo + FireHi + LighLo + LighHi) / 2) * AttackSpeed
  4013. TotalDps := PhysDps + EleDps
  4014.  
  4015. Result = %Result%`nPhys DPS: %PhysDps%`nElem DPS: %EleDps%`nTotal DPS: %TotalDps%
  4016.  
  4017. ; Only show Q20 values if item is not Q20
  4018. If (Quality < 20) {
  4019. TotalPhysMult := (PhysMult + Quality + 100) / 100
  4020. BasePhysDps := PhysDps / TotalPhysMult
  4021. Q20Dps := BasePhysDps * ((PhysMult + 120) / 100) + EleDps
  4022.  
  4023. Result = %Result%`nQ20 DPS: %Q20Dps%
  4024. }
  4025.  
  4026. return Result
  4027. }
  4028.  
  4029. ParseItemName(ItemDataChunk, ByRef ItemName, ByRef ItemTypeName)
  4030. {
  4031. Loop, Parse, ItemDataChunk, `n, `r
  4032. {
  4033. If (A_Index == 1)
  4034. {
  4035. IfNotInString, A_LoopField, Rarity:
  4036. {
  4037. return
  4038. }
  4039. Else
  4040. {
  4041. Continue
  4042. }
  4043. }
  4044. If (StrLen(A_LoopField) == 0 or A_LoopField == "--------" or A_Index > 3)
  4045. {
  4046. return
  4047. }
  4048. If (A_Index = 2)
  4049. {
  4050. ItemName := A_LoopField
  4051. }
  4052. If (A_Index = 3)
  4053. {
  4054. ItemTypeName := A_LoopField
  4055. }
  4056. }
  4057. }
  4058.  
  4059. GemIsValuable(ItemName)
  4060. {
  4061. Loop, Read, %A_WorkingDir%\data\ValuableGems.txt
  4062. {
  4063. IfInString, ItemName, %A_LoopReadLine%
  4064. {
  4065. return True
  4066. }
  4067. }
  4068. return False
  4069. }
  4070.  
  4071. UniqueIsValuable(ItemName)
  4072. {
  4073. Loop, Read, %A_WorkingDir%\data\ValuableUniques.txt
  4074. {
  4075. IfInString, ItemName, %A_LoopReadLine%
  4076. {
  4077. return True
  4078. }
  4079. }
  4080. return False
  4081. }
  4082.  
  4083. GemIsDropOnly(ItemName)
  4084. {
  4085. Loop, Read, %A_WorkingDir%\data\DropOnlyGems.txt
  4086. {
  4087. IfInString, ItemName, %A_LoopReadLine%
  4088. {
  4089. return True
  4090. }
  4091. }
  4092. return False
  4093. }
  4094.  
  4095. ParseLinks(ItemData)
  4096. {
  4097. HighestLink := 0
  4098. Loop, Parse, ItemData, `n, `r
  4099. {
  4100. IfInString, A_LoopField, Sockets
  4101. {
  4102. LinksString := GetColonValue(A_LoopField)
  4103. If (RegExMatch(LinksString, ".-.-.-.-.-."))
  4104. {
  4105. HighestLink := 6
  4106. Break
  4107. }
  4108. If (RegExMatch(LinksString, ".-.-.-.-."))
  4109. {
  4110. HighestLink := 5
  4111. Break
  4112. }
  4113. If (RegExMatch(LinksString, ".-.-.-."))
  4114. {
  4115. HighestLink := 4
  4116. Break
  4117. }
  4118. If (RegExMatch(LinksString, ".-.-."))
  4119. {
  4120. HighestLink := 3
  4121. Break
  4122. }
  4123. If (RegExMatch(LinksString, ".-."))
  4124. {
  4125. HighestLink := 2
  4126. Break
  4127. }
  4128. }
  4129. }
  4130. return HighestLink
  4131. }
  4132.  
  4133. ; converts a currency stack to chaos
  4134. ; by looking up the conversion ratio
  4135. ; from CurrencyRates.txt
  4136. ConvertCurrency(ItemName, ItemStats)
  4137. {
  4138. If (InStr(ItemName, "Shard"))
  4139. {
  4140. IsShard := True
  4141. ItemName := "Orb of " . SubStr(ItemName, 1, -StrLen(" Shard"))
  4142. }
  4143. If (InStr(ItemName, "Fragment"))
  4144. {
  4145. IsFragment := True
  4146. ItemName := "Scroll of Wisdom"
  4147. }
  4148. StackSize := SubStr(ItemStats, StrLen("Stack Size: "))
  4149. StringSplit, StackSizeParts, StackSize, /
  4150. If (IsShard or IsFragment)
  4151. {
  4152. SetFormat, FloatFast, 5.3
  4153. StackSize := StackSizeParts1 / StackSizeParts2
  4154. }
  4155. Else
  4156. {
  4157. SetFormat, FloatFast, 5.2
  4158. StackSize := StackSizeParts1
  4159. }
  4160. ValueInChaos := 0
  4161. Loop, Read, %A_WorkingDir%\data\CurrencyRates.txt
  4162. {
  4163. IfInString, A_LoopReadLine, `;
  4164. {
  4165. ; comment
  4166. Continue
  4167. }
  4168. If (StrLen(A_LoopReadLine) <= 2)
  4169. {
  4170. ; blank line (at most \r\n)
  4171. Continue
  4172. }
  4173. IfInString, A_LoopReadLine, %ItemName%
  4174. {
  4175. StringSplit, LineParts, A_LoopReadLine, |
  4176. ChaosRatio := LineParts2
  4177. StringSplit, ChaosRatioParts,ChaosRatio, :
  4178. ChaosMult := ChaosRatioParts2 / ChaosRatioParts1
  4179. ValueInChaos := (ChaosMult * StackSize)
  4180. ; msgbox, Name: %ItemName%`, StackSize: %StackSize%`, ChaosMult: %ChaosMult%`, ValueInChaos: %ValueInChaos%
  4181. }
  4182. }
  4183. return ValueInChaos
  4184. }
  4185.  
  4186. ; Parse unique affixes from text file database.
  4187. ; Has wanted side effect of populating AffixLines "array" vars.
  4188. ; return True if the unique was found the database
  4189. ParseUnique(ItemName)
  4190. {
  4191. Global
  4192. Local Delim
  4193. Delim := "|"
  4194. ResetAffixDetailVars()
  4195. UniqueFound := False
  4196. Loop, Read, %A_WorkingDir%\data\Uniques.txt
  4197. {
  4198. IfInString, A_LoopReadLine, `;
  4199. {
  4200. ; comment
  4201. Continue
  4202. }
  4203. If (StrLen(A_LoopReadLine) <= 2)
  4204. {
  4205. ; blank line
  4206. ; 2 characters at most: \r\n. Don't bother
  4207. ; checking if they are actually control chars
  4208. ; or normal letters.
  4209. Continue
  4210. }
  4211. IfInString, A_LoopReadLine, %ItemName%
  4212. {
  4213. StringSplit, LineParts, A_LoopReadLine, |
  4214. NumLineParts := LineParts0
  4215. NumAffixLines := NumLineParts-1 ; exclude item name at first pos
  4216. Local UniqueFound
  4217. UniqueFound := True
  4218. Local AppendImplicitSep
  4219. AppendImplicitSep := False
  4220. Idx := 1
  4221. Loop, % (NumLineParts)
  4222. {
  4223. If (A_Index > 1)
  4224. {
  4225. Local CurLinePart
  4226. Local AffixLine
  4227. Local ValueRange
  4228. CurLinePart := LineParts%A_Index%
  4229. IfInString, CurLinePart, :
  4230. {
  4231. StringSplit, CurLineParts, CurLinePart, :
  4232. AffixLine := CurLineParts2
  4233. ValueRange := CurLineParts1
  4234. IfInString, ValueRange, @
  4235. {
  4236. AppendImplicitSep := True
  4237. StringReplace, ValueRange, ValueRange, @
  4238. }
  4239. ; Make "Attacks per Second" float ranges to be like a double range.
  4240. ; Since a 2 decimal precision float value is 4 chars wide (#.##)
  4241. ; when including the radix point this means a float value range
  4242. ; is then 9 chars wide. Replacing the "-" with a "," effectively
  4243. ; makes it so that float ranges are treated as double ranges and
  4244. ; distributes the bounds over both value range fields. This may
  4245. ; or may not be desirable. On the plus side things will align
  4246. ; nicely, but on the negative side, it will be a bit unclearer that
  4247. ; both float values constitute a range and not two isolated values.
  4248. ValueRange := RegExReplace(ValueRange, "(\d+\.\d+)-(\d+\.\d+)", "$1,$2")
  4249. IfInString, ValueRange, `,
  4250. {
  4251. ; double range
  4252. StringSplit, ValueRangeParts, ValueRange, `,
  4253. Local ValueRangeParts
  4254. Local LowerBound
  4255. Local UpperBound
  4256. LowerBound := ValueRangeParts1
  4257. UpperBound := ValueRangeParts2
  4258. ValueRange := StrPad(LowerBound, ValueRangeFieldWidth, "left") . AffixDetailDelimiter . StrPad(UpperBound, ValueRangeFieldWidth, "left")
  4259. }
  4260. ProcessedLine := AffixLine . Delim . StrPad(ValueRange, ValueRangeFieldWidth, "left")
  4261. If (AppendImplicitSep)
  4262. {
  4263. ProcessedLine := ProcessedLine . "`n" . "--------"
  4264. AppendImplicitSep := False
  4265. }
  4266. AffixLines%Idx% := ProcessedLine
  4267. }
  4268. Else
  4269. {
  4270. AffixLines%Idx% := CurLinePart
  4271. }
  4272. Idx += 1
  4273. }
  4274. }
  4275. }
  4276. }
  4277.  
  4278. return UniqueFound
  4279. }
  4280.  
  4281. ; Main parse function
  4282. ParseItemData(ItemData, ByRef RarityLevel="", ByRef NumPrefixes="", ByRef NumSuffixes="")
  4283. {
  4284. ; global var access to support user options
  4285. Global ShowItemLevel
  4286. Global ShowMaxSockets
  4287. Global ShowDamageCalculations
  4288. Global ShowAffixTotals
  4289. Global ShowAffixDetails
  4290. Global ShowCurrencyValueInChaos
  4291. Global ShowGemEvaluation
  4292. Global ShowUniqueEvaluation
  4293. Global GemQualityValueThreshold
  4294. Global MarkHighLinksAsValuable
  4295.  
  4296. ; these 4 actually need to be global because
  4297. ; they are used in other functions
  4298. Global ItemBaseType
  4299. Global ItemSubType
  4300. Global ItemGripType
  4301. Global ItemDataRarity
  4302.  
  4303. ; marked " ; d" for debugging (to easily search & replace)
  4304. ; Global ItemData ; d
  4305. ; Global IsWeapon ; d
  4306. ; Global IsUnidentified ; d
  4307. ; Global IsCurrency ; d
  4308. ; Global ItemLevel ; d
  4309. ; Global ItemDataNamePlate ; d
  4310. ; Global ItemDataStats ; d
  4311. ; Global ItemDataRequirements ; d
  4312. ; Global RequiredAttributes ; d
  4313. ; Global ItemName ; d
  4314. ; Global ItemTypeName ; d
  4315. ; Global RequiredLevel ; d
  4316. ; Global RequiredAttributeValues ; d
  4317. ; Global ItemQuality ; d
  4318. ; Global ItemDataPartsIndexLast ; d
  4319. ; Global ItemDataPartsLast ; d
  4320. ; Global RarityLevel ; d
  4321. ; Global IsFlask ; d
  4322. ; Global IsUnique ; d
  4323. ; Global ItemDataImplicitMods ; d
  4324. ; Global NumPrefixes ; d
  4325. ; Global NumSuffixes ; d
  4326. ; Global NumAffixLines ; d
  4327. ; Global TotalAffixes ; d
  4328. ; Global ItemDataAffixes ; d
  4329. ; Global ItemDataStats ; d
  4330. ; Global AugmentedStats ; d
  4331.  
  4332. ; ItemDataParts0 =
  4333. ; Loop, 10
  4334. ; {
  4335. ; ItemDataParts%A_Index% =
  4336. ; }
  4337.  
  4338. ItemDataPartsIndexLast =
  4339. ItemDataPartsIndexAffixes =
  4340. ItemDataPartsLast =
  4341. ItemDataNamePlate =
  4342. ItemDataStats =
  4343. ItemDataAffixes =
  4344. ItemDataRequirements =
  4345. ItemDataRarity =
  4346. ItemDataLinks =
  4347. ItemName =
  4348. ItemTypeName =
  4349. ItemQuality =
  4350. ItemLevel =
  4351. ItemMaxSockets =
  4352. BaseLevel =
  4353. RarityLevel =
  4354. TempResult =
  4355.  
  4356. IsWeapon := False
  4357. IsQuiver := False
  4358. IsFlask := False
  4359. IsGem := False
  4360. IsCurrency := False
  4361. IsUnidentified := False
  4362. IsBelt := False
  4363. IsRing := False
  4364. IsUnsetRing := False
  4365. IsBow := False
  4366. IsAmulet := False
  4367. IsSingleSocket := False
  4368. IsFourSocket := False
  4369. IsThreeSocket := False
  4370. IsMap := False
  4371. IsUnique := False
  4372. IsRare := False
  4373.  
  4374. ItemBaseType =
  4375. ItemSubType =
  4376. ItemGripType =
  4377.  
  4378. ; AHK only allows splitting on single chars, so first
  4379. ; replace the split string (\r\n--------\r\n) with AHK's escape char (`)
  4380. ; then do the actual string splitting...
  4381. StringReplace, TempResult, ItemData, `r`n--------`r`n, ``, All
  4382. StringSplit, ItemDataParts, TempResult, ``,
  4383.  
  4384. ItemDataNamePlate := ItemDataParts1
  4385. ItemDataStats := ItemDataParts2
  4386. ItemDataRequirements := ItemDataParts3
  4387.  
  4388. ; ParseRequirements(ItemDataRequirements, RequiredLevel, RequiredAttributes, RequiredAttributeValues)
  4389. ; msgbox, RequiredLevel: %RequiredLevel%`, RequiredAttributes: %RequiredAttributes%`, RequiredAttributeValues: %RequiredAttributeValues%
  4390.  
  4391. ParseItemName(ItemDataNamePlate, ItemName, ItemTypeName)
  4392.  
  4393. ; assign length of the "array" so we can either grab the
  4394. ; last item (if non unique) or the item before last
  4395. ItemDataPartsIndexLast := ItemDataParts0
  4396. ItemDataPartsLast := ItemDataParts%ItemDataPartsIndexLast%
  4397. IfInString, ItemDataPartsLast, Unidentified
  4398. {
  4399. IsUnidentified := True
  4400. }
  4401.  
  4402. ItemQuality := ParseQuality(ItemDataStats)
  4403.  
  4404. ; this function should return the second part of the "Rarity: ..." line
  4405. ; in the case of "Rarity: Unique" it should return "Unique"
  4406. ItemDataRarity := ParseRarity(ItemDataNamePlate)
  4407.  
  4408. ItemDataLinks := ParseLinks(ItemData)
  4409.  
  4410. IsUnique := False
  4411. IfInString, ItemDataRarity, Unique
  4412. {
  4413. IsUnique := True
  4414. }
  4415.  
  4416. IfInString, ItemDataRarity, Rare
  4417. {
  4418. IsRare := True
  4419. }
  4420.  
  4421. IsGem := (InStr(ItemDataRarity, "Gem"))
  4422. IsCurrency := (InStr(ItemDataRarity, "Currency"))
  4423.  
  4424. If (IsGem)
  4425. {
  4426. RarityLevel := 0
  4427. ItemLevel := ParseItemLevel(ItemData, "Level:")
  4428. ItemLevelWord := "Gem Level:"
  4429. }
  4430. Else
  4431. {
  4432. If (IsCurrency and ShowCurrencyValueInChaos == 1)
  4433. {
  4434. ValueInChaos := ConvertCurrency(ItemName, ItemDataStats)
  4435. If (ValueInChaos)
  4436. {
  4437. CurrencyDetails := ValueInChaos . " Chaos"
  4438. }
  4439. }
  4440. Else
  4441. {
  4442. RarityLevel := CheckRarityLevel(ItemDataRarity)
  4443. ItemLevel := ParseItemLevel(ItemData)
  4444. ItemLevelWord := "Item Level:"
  4445. ParseItemType(ItemDataStats, ItemDataNamePlate, ItemBaseType, ItemSubType, ItemGripType)
  4446. }
  4447. }
  4448.  
  4449. IsBow := (ItemSubType == "Bow")
  4450. IsFlask := (ItemSubType == "Flask")
  4451. IsBelt := (ItemSubType == "Belt")
  4452. IsRing := (ItemSubType == "Ring")
  4453. IsUnsetRing := (IsRing and InStr(ItemDataNamePlate, "Unset Ring"))
  4454. IsAmulet := (ItemSubType == "Amulet")
  4455. IsSingleSocket := (IsUnsetRing)
  4456. IsFourSocket := (ItemSubType == "Gloves" or ItemSubType == "Boots" or ItemSubType == "Helmet")
  4457. IsThreeSocket := ((ItemGripType == "1H" or ItemSubType == "Shield") and Not IsBow)
  4458. IsQuiver := (ItemSubType == "Quiver")
  4459. IsWeapon := (ItemBaseType == "Weapon")
  4460. IsMap := (ItemBaseType == "Map")
  4461.  
  4462. If (Not ItemName)
  4463. {
  4464. return
  4465. }
  4466.  
  4467. If (IsFlask or IsUnique)
  4468. {
  4469. ; uniques as well as flasks have descriptive text as last item,
  4470. ; so decrement item index to get to the item before last one
  4471. ItemDataPartsIndexAffixes := ItemDataPartsIndexLast - 1
  4472. }
  4473. Else
  4474. {
  4475. ItemDataPartsIndexAffixes := ItemDataPartsIndexLast
  4476. }
  4477.  
  4478. If (ItemDataPartsIndexAffixes = 0)
  4479. {
  4480. ; ItemDataParts doesn't have the parts/text we need. Bail.
  4481. ; This might be because the clipboard is completely empty.
  4482. return
  4483. }
  4484.  
  4485. ; hopefully this should now hold the part of the text that
  4486. ; deals with affixes
  4487. ItemDataAffixes := ItemDataParts%ItemDataPartsIndexAffixes%
  4488.  
  4489. ItemDataStats := ItemDataParts%ItemDataParts%2
  4490.  
  4491. If (RarityLevel > 1)
  4492. {
  4493. ParseAffixes(ItemDataAffixes, ItemLevel, ItemQuality, NumPrefixes, NumSuffixes)
  4494. TotalAffixes := NumPrefixes + NumSuffixes
  4495. }
  4496.  
  4497. ; Start assembling the text for the tooltip
  4498. TT := ItemName
  4499. If (ItemTypeName)
  4500. {
  4501. TT := TT . "`n" . ItemTypeName
  4502. }
  4503.  
  4504. If (ShowItemLevel == 1 and Not IsMap)
  4505. {
  4506. TT := TT . "`n"
  4507. TT := TT . ItemLevelWord . " " . StrPad(ItemLevel, 3, Side="left")
  4508. If (Not IsFlask)
  4509. {
  4510. BaseLevel := CheckBaseLevel(ItemTypeName)
  4511. If (BaseLevel)
  4512. {
  4513. TT := TT . "`n" . "Base Level: " . StrPad(BaseLevel, 3, Side="left")
  4514. }
  4515. }
  4516. }
  4517.  
  4518. If (ShowMaxSockets == 1 and Not (IsFlask or IsGem or IsCurrency or IsBelt or IsQuiver or IsMap or IsAmulet))
  4519. {
  4520. If (ItemLevel >= 50)
  4521. {
  4522. ItemMaxSockets = 6
  4523. }
  4524. Else If (ItemLevel >= 35)
  4525. {
  4526. ItemMaxSockets = 5
  4527. }
  4528. Else If (ItemLevel >= 28)
  4529. {
  4530. ItemMaxSockets = 4
  4531. }
  4532. Else If (ItemLevel >= 15)
  4533. {
  4534. ItemMaxSockets = 3
  4535. }
  4536. Else
  4537. {
  4538. ItemMaxSockets = 2
  4539. }
  4540.  
  4541. If(IsFourSocket and ItemMaxSockets > 4)
  4542. {
  4543. ItemMaxSockets = 4
  4544. }
  4545. Else If(IsThreeSocket and ItemMaxSockets > 3)
  4546. {
  4547. ItemMaxSockets = 3
  4548. }
  4549. Else If(IsSingleSocket)
  4550. {
  4551. ItemMaxSockets = 1
  4552. }
  4553.  
  4554. If (Not IsRing or IsUnsetRing)
  4555. {
  4556. TT := TT . "`n"
  4557. TT := TT . "Max Sockets: "
  4558. TT := TT . ItemMaxSockets
  4559. }
  4560. }
  4561.  
  4562. If (IsGem and ShowGemEvaluation == 1)
  4563. {
  4564. SepAdded := False
  4565. If (ItemQuality > 0)
  4566. {
  4567. TT = %TT%`n--------
  4568. SepAdded := True
  4569. TT = %TT%`n+%ItemQuality%`%
  4570. }
  4571. If (ItemQuality >= GemQualityValueThreshold or GemIsValuable(ItemName))
  4572. {
  4573. If (Not SepAdded)
  4574. {
  4575. TT = %TT%`n--------
  4576. SepAdded := True
  4577. }
  4578. TT = %TT%`nValuable
  4579. }
  4580. If (GemIsDropOnly(ItemName))
  4581. {
  4582. If (Not SepAdded)
  4583. {
  4584. TT = %TT%`n--------
  4585. SepAdded := True
  4586. }
  4587. TT = %TT%`nDrop Only
  4588. }
  4589. }
  4590.  
  4591. If (IsCurrency)
  4592. {
  4593. TT = %TT%%CurrencyDetails%
  4594. }
  4595.  
  4596. If (IsWeapon and ShowDamageCalculations == 1)
  4597. {
  4598. TT := TT . AssembleDamageDetails(ItemData)
  4599. }
  4600.  
  4601. If (IsMap)
  4602. {
  4603. Global mapList
  4604. Global uniqueMapList
  4605. if (IsUnique)
  4606. {
  4607. MapDescription := uniqueMapList[ItemSubType]
  4608. }
  4609. else
  4610. {
  4611. MapDescription := mapList[ItemSubType]
  4612. }
  4613.  
  4614. TT = %TT%`n%MapDescription%
  4615. }
  4616.  
  4617. ; Append affix info if rarity is greater than normal (white)
  4618. ; Affix total statistic
  4619. If (ShowAffixTotals = 1)
  4620. {
  4621. If (RarityLevel > 1 and RarityLevel < 4)
  4622. {
  4623. If (NumPrefixes = 1)
  4624. {
  4625. WordPrefixes = Prefix
  4626. }
  4627. Else
  4628. {
  4629. WordPrefixes = Prefixes
  4630. }
  4631. If (NumSuffixes = 1)
  4632. {
  4633. WordSuffixes = Suffix
  4634. }
  4635. Else
  4636. {
  4637. WordSuffixes = Suffixes
  4638. }
  4639.  
  4640. PrefixLine =
  4641. If (NumPrefixes > 0)
  4642. {
  4643. PrefixLine = `n %NumPrefixes% %WordPrefixes%
  4644. }
  4645.  
  4646. SuffixLine =
  4647. If (NumSuffixes > 0)
  4648. {
  4649. SuffixLine = `n %NumSuffixes% %WordSuffixes%
  4650. }
  4651.  
  4652. AffixStats =
  4653. If (TotalAffixes > 0 and Not IsUnidentified)
  4654. {
  4655. AffixStats = Affixes (%TotalAffixes%):%PrefixLine%%SuffixLine%
  4656. TT = %TT%`n--------`n%AffixStats%
  4657. }
  4658. }
  4659. Else
  4660. {
  4661. If (ItemDataRarity == "Unique")
  4662. {
  4663. If (ParseUnique(ItemName))
  4664. {
  4665. AffixDetails := AssembleAffixDetails()
  4666. TT = %TT%`n--------%AffixDetails%
  4667. }
  4668. Else If(Not IsMap)
  4669. {
  4670. If (IsUnidentified)
  4671. {
  4672. TT = %TT%`n--------`nUnidentified
  4673. }
  4674. Else
  4675. {
  4676. TT = %TT%`n--------`nUnique item currently not supported
  4677. }
  4678. }
  4679. }
  4680. }
  4681. }
  4682.  
  4683. ; Detailed affix range infos
  4684. If (ShowAffixDetails = 1)
  4685. {
  4686. If (Not IsFlask AND Not IsUnidentified)
  4687. {
  4688. If (RarityLevel > 1 AND RarityLevel < 4)
  4689. {
  4690. AffixDetails := AssembleAffixDetails()
  4691. TT = %TT%`n--------%AffixDetails%
  4692. }
  4693. Else If ((ItemDataRarity == "Unique"))
  4694. {
  4695. If (Not ShowAffixTotals)
  4696. {
  4697. ParseUnique(ItemName)
  4698. TT = %TT%`n--------%AffixDetails%
  4699. }
  4700. }
  4701. }
  4702. }
  4703.  
  4704. If ((IsUnique AND (ShowUniqueEvaluation == 1) AND UniqueIsValuable(ItemName)) OR (MarkHighLinksAsValuable = 1 AND (IsUnique OR IsRare) AND ItemDataLinks >= 5))
  4705. {
  4706. TT = %TT%`n--------`nValuable
  4707. }
  4708.  
  4709. ;msgbox, %TT%
  4710. return TT
  4711. }
  4712.  
  4713. ; Show tooltip, with fixed width font
  4714. ShowToolTip(String)
  4715. {
  4716. ; Get position of mouse cursor
  4717. Global X
  4718. Global Y
  4719. MouseGetPos, X, Y
  4720.  
  4721. ToolTip, %String%, X - 135, Y + 35
  4722. Global FixedFont
  4723. SetFont(FixedFont)
  4724.  
  4725. ; Set up count variable and start timer for tooltip timeout
  4726. Global ToolTipTimeout := 0
  4727. SetTimer, ToolTipTimer, 100
  4728. }
  4729.  
  4730. ; ############## TESTS #################
  4731.  
  4732. TestCaseSeparator := "####################"
  4733.  
  4734. RunRareTestSuite(Path, SuiteNumber)
  4735. {
  4736. Global TestCaseSeparator
  4737.  
  4738. NumTestCases := 0
  4739. Loop, Read, %Path%
  4740. {
  4741. ; msgbox, % TestCaseText
  4742. IfInString, A_LoopReadLine, %TestCaseSeparator%
  4743. {
  4744. NumTestCases += 1
  4745. Continue
  4746. }
  4747. TestCaseText := A_LoopReadLine
  4748. TestCases%NumTestCases% := TestCases%NumTestCases% . TestCaseText . "`r`n"
  4749. }
  4750.  
  4751. ; msgbox, NumTestCases: %NumTestCases%
  4752. Failures := 0
  4753. Successes := 0
  4754. FailureNumbers =
  4755. TestCase =
  4756. Loop, %NumTestCases%
  4757. {
  4758. TestCase := TestCases%A_Index%
  4759.  
  4760. NumPrefixes := 0
  4761. NumSuffixes := 0
  4762. RarityLevel := 0
  4763. TestCaseResult := ParseItemData(TestCase, RarityLevel, NumPrefixes, NumSuffixes)
  4764.  
  4765. StringReplace, TempResult, TestCaseResult, --------, ``, All
  4766. StringSplit, TestCaseResultParts, TempResult, ``
  4767.  
  4768. NameAndDPSPart := TestCaseResultParts1
  4769. TotalAffixStatsPart := TestCaseResultParts2
  4770. AffixCompositionPart := TestCaseResultParts3
  4771.  
  4772. ; failure conditions
  4773. TotalAffixes := 0
  4774. TotalAffixes := NumPrefixes + NumSuffixes
  4775. InvalidTotalAffixNumber := (TotalAffixes > 6)
  4776. BracketLookupFailed := InStr(TestCaseResult, "n/a")
  4777. CompositeRangeCalcFailed := InStr(TestCaseResult, " - ")
  4778.  
  4779. Prefixes := 0
  4780. Suffixes := 0
  4781. CompPrefixes := 0
  4782. CompSuffixes := 0
  4783. ExtractTotalAffixBalance(AffixCompositionPart, Prefixes, Suffixes, CompPrefixes, CompSuffixes)
  4784.  
  4785. HasDanglingComposites := False
  4786. If (Mod(CompPrefixes, 2)) ; True, if not evenly divisible by 2
  4787. {
  4788. HasDanglingComposites := True
  4789. }
  4790. If (Mod(CompSuffixes, 2))
  4791. {
  4792. HasDanglingComposites := True
  4793. }
  4794.  
  4795. TotalCountByAffixTypes := (Floor(CompPrefixes / 2) + Floor(CompSuffixes / 2) + Prefixes + Suffixes)
  4796.  
  4797. ; msgbox, TotalAffixes: %TotalAffixes%`, TotalCountByAffixTypes: %TotalCountByAffixTypes%
  4798. AffixTypesCountedIncorrectly := (Not (TotalCountByAffixTypes == TotalAffixes))
  4799. If (InvalidTotalAffixNumber or BracketLookupFailed or CompositeRangeCalcFailed or HasDanglingComposites or AffixTypesCountedIncorrectly)
  4800. {
  4801. Failures += 1
  4802. FailureNumbers := FailureNumbers . A_Index . ","
  4803. }
  4804. Else
  4805. {
  4806. Successes += 1
  4807. }
  4808. ; needed so global variables can be yanked from memory and reset between calls
  4809. ; (if you reload the script really fast globals vars that are out of date can
  4810. ; cause failures when there are none)
  4811. Sleep, 1
  4812. }
  4813.  
  4814. Result := "Suite " . SuiteNumber . ": " . StrPad(Successes, 5, "left") . " OK" . ", " . StrPad(Failures, 5, "left") . " Failed"
  4815. If (Failures > 0)
  4816. {
  4817. FailureNumbers := SubStr(FailureNumbers, 1, -1)
  4818. Result := Result . " (" . FailureNumbers . ")"
  4819. }
  4820. return Result
  4821. }
  4822.  
  4823. RunUniqueTestSuite(Path, SuiteNumber)
  4824. {
  4825. Global TestCaseSeparator
  4826.  
  4827. NumTestCases := 0
  4828. Loop, Read, %Path%
  4829. {
  4830. IfInString, A_LoopReadLine, %TestCaseSeparator%
  4831. {
  4832. NumTestCases += 1
  4833. Continue
  4834. }
  4835. TestCaseText := A_LoopReadLine
  4836. TestCases%NumTestCases% := TestCases%NumTestCases% . TestCaseText . "`r`n"
  4837. }
  4838.  
  4839. Failures := 0
  4840. Successes := 0
  4841. FailureNumbers =
  4842. TestCase =
  4843. Loop, %NumTestCases%
  4844. {
  4845. TestCase := TestCases%A_Index%
  4846. TestCaseResult := ParseItemData(TestCase)
  4847.  
  4848. FailedToSepImplicit := InStr(TestCaseResult, "@") ; failed to properly seperate implicit from normal affixes
  4849. ; TODO: add more unique item test failure conditions
  4850.  
  4851. If (FailedToSepImplicit)
  4852. {
  4853. Failures += 1
  4854. FailureNumbers := FailureNumbers . A_Index . ","
  4855. }
  4856. Else
  4857. {
  4858. Successes += 1
  4859. }
  4860. ; needed so global variables can be yanked from memory and reset between calls
  4861. ; (if you reload the script really fast globals vars that are out of date can
  4862. ; cause failures where there are none)
  4863. Sleep, 1
  4864. }
  4865.  
  4866. Result := "Suite " . SuiteNumber . ": " . StrPad(Successes, 5, "left") . " OK" . ", " . StrPad(Failures, 5, "left") . " Failed"
  4867. If (Failures > 0)
  4868. {
  4869. FailureNumbers := SubStr(FailureNumbers, 1, -1)
  4870. Result := Result . " (" . FailureNumbers . ")"
  4871. }
  4872. return Result
  4873. }
  4874.  
  4875. RunAllTests()
  4876. {
  4877. ; change this to the number of available test suites
  4878. TestDataBasePath = %A_WorkingDir%\extras\tests
  4879.  
  4880. NumRareTestSuites := 4
  4881. RareResults := "Rare Items"
  4882. Loop, %NumRareTestSuites%
  4883. {
  4884. If (A_Index > 0) ; change condition to only run certain tests
  4885. {
  4886. TestSuitePath = %TestDataBasePath%\Rares%A_Index%.txt
  4887. TestSuiteResult := RunRareTestSuite(TestSuitePath, A_Index)
  4888. RareResults := RareResults . "`n " . TestSuiteResult
  4889. }
  4890. }
  4891.  
  4892. NumUniqueTestSuites := 1
  4893. UniqResults := "Unique Items"
  4894. Loop, %NumUniqueTestSuites%
  4895. {
  4896. If (A_Index > 0) ; change condition to only run certain tests
  4897. {
  4898. TestSuitePath = %TestDataBasePath%\Uniques%A_Index%.txt
  4899. TestSuiteResult := RunUniqueTestSuite(TestSuitePath, A_Index)
  4900. UniqResults := UniqResults . "`n " . TestSuiteResult
  4901. }
  4902. }
  4903.  
  4904. msgbox, %RareResults%`n`n%UniqResults%
  4905. }
  4906.  
  4907. If (RunTests)
  4908. {
  4909. RunAllTests()
  4910. }
  4911.  
  4912. ; ########### TIMERS ############
  4913.  
  4914. ; Tick every 100 ms
  4915. ; Remove tooltip if mouse is moved or 5 seconds pass
  4916. ToolTipTimer:
  4917. ToolTipTimeout += 1
  4918. MouseGetPos, CurrX, CurrY
  4919. MouseMoved := (CurrX - X)**2 + (CurrY - Y)**2 > MouseMoveThreshold**2
  4920. If (MouseMoved or ((UseTooltipTimeout = 1) and (ToolTipTimeout >= ToolTipTimeoutTicks)))
  4921. {
  4922. SetTimer, ToolTipTimer, Off
  4923. ToolTip
  4924. }
  4925. return
  4926.  
  4927. OnClipBoardChange:
  4928. Global OnlyActiveIfPOEIsFront
  4929. If (OnlyActiveIfPOEIsFront)
  4930. {
  4931. ; do nothing if Path of Exile isn't the foremost window
  4932. IfWinActive, Path of Exile ahk_class Direct3DWindowClass
  4933. {
  4934. ParseClipBoardChanges()
  4935. }
  4936. }
  4937. Else
  4938. {
  4939. ; if running tests parse clipboard regardless if PoE is foremost
  4940. ; so we can check individual cases from test case text files
  4941. ParseClipBoardChanges()
  4942. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement